lib/write_xlsx/chart.rb in write_xlsx-0.70.0 vs lib/write_xlsx/chart.rb in write_xlsx-0.71.0

- old
+ new

@@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- require 'write_xlsx/package/xml_writer_simple' require 'write_xlsx/utility' require 'write_xlsx/chart/axis' +require 'write_xlsx/chart/caption' +require 'write_xlsx/chart/series' module Writexlsx class Table include Writexlsx::Utility @@ -31,471 +33,10 @@ def attributes ['val', 1] end end - # ==SYNOPSIS - # - # To create a simple Excel file with a chart using WriteXLSX: - # - # require 'rubygems' - # require 'write_xlsx' - # - # workbook = WriteXLSX.new('chart.xlsx') - # worksheet = workbook.add_worksheet - # - # # Add the worksheet data the chart refers to. - # data = [ - # [ 'Category', 2, 3, 4, 5, 6, 7 ], - # [ 'Value', 1, 4, 5, 2, 1, 5 ] - # ] - # - # worksheet.write( 'A1', data ) - # - # # Add a worksheet chart. - # chart = workbook.add_chart( type => 'column' ) - # - # # Configure the chart. - # chart.add_series( - # :categories => '=Sheet1!$A$2:$A$7', - # :values => '=Sheet1!$B$2:$B$7' - # ) - # - # workbook.close - # - # ==DESCRIPTION - # - # The Chart is an abstract base class for modules that implement - # charts in WriteXLSX. The information below is applicable to all of - # the available subclasses. - # - # The Chart isn't used directly. A chart object is created via - # the {WriteXLXS#add_chart()} - # method where the chart type is specified: - # - # chart = workbook.add_chart( :type => 'column' ) - # - # Currently the supported chart types are: - # - # ===area - # Creates an Area (filled line) style chart. See Writexlsx::Chart::Area. - # - # ===bar - # Creates a Bar style (transposed histogram) chart. See Writexlsx::Chart::Bar. - # - # ===column - # Creates a Column style (histogram) chart. See Writexlsx::Chart::Column. - # - # ===line - # Creates a Line style chart. See Writexlsx::Chart::Line. - # - # ===pie - # Creates a Pie style chart. See Writexlsx::Chart::Pie. - # - # ===scatter - # Creates a Scatter style chart. See Writexlsx::Chart::Scatter. - # - # ===stock - # Creates a Stock style chart. See Writexlsx::Chart::Stock. - # - # ===radar - # Creates a Radar style chart. See Writexlsx::Chart::Radar. - # - # Chart subtypes are also supported in some cases: - # - # workbook.add_chart(:type => 'bar', :subtype => 'stacked') - # - # The currently available subtypes are: - # - # area - # stacked - # percent_stacked - # - # bar - # stacked - # percent_stacked - # - # column - # stacked - # percent_stacked - # - # scatter - # straight_with_markers - # straight - # smooth_with_markers - # smooth - # - # radar - # with_markers - # filled - # - # ==CHART FORMATTING - # - # The following chart formatting properties can be set for any chart object - # that they apply to (and that are supported by WriteXLSX) such - # as chart lines, column fill areas, plot area borders, markers and other - # chart elements documented above. - # - # line - # border - # fill - # marker - # trendline - # data_labels - # - # Chart formatting properties are generally set using hash refs. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :line => { color => 'blue' } - # ) - # - # In some cases the format properties can be nested. For example a marker - # may contain border and fill sub-properties. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :line => { color => 'blue' }, - # :marker => { - # :type => 'square', - # :size => 5, - # :border => { color => 'red' }, - # :fill => { color => 'yellow' } - # } - # ) - # - # ===Line - # - # The line format is used to specify properties of line objects that appear - # in a chart such as a plotted line on a chart or a border. - # - # The following properties can be set for line formats in a chart. - # - # none - # color - # width - # dash_type - # The none property is uses to turn the line off (it is always on by default - # except in Scatter charts). This is useful if you wish to plot a series - # with markers but without a line. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :line => { none => 1 } - # ) - # The color property sets the color of the line. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :line => { color => 'red' } - # ) - # The available colors are shown in the main WriteXLSX documentation. - # It is also possible to set the color of a line with a HTML style RGB color: - # - # chart.add_series( - # :line => { color => '#FF0000' } - # ) - # The width property sets the width of the line. It should be specified - # in increments of 0.25 of a point as in Excel. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :line => { width => 3.25 } - # ) - # The dash_type property sets the dash style of the line. - # - # chart->add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :line => { dash_type => 'dash_dot' } - # ) - # The following dash_type values are available. They are shown in the - # order that they appear in the Excel dialog. - # - # solid - # round_dot - # square_dot - # dash - # dash_dot - # long_dash - # long_dash_dot - # long_dash_dot_dot - # The default line style is solid. - # - # More than one line property can be specified at time: - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :line => { - # :color => 'red', - # :width => 1.25, - # :dash_type => 'square_dot' - # } - # ) - # ===Border - # - # The border property is a synonym for line. - # - # It can be used as a descriptive substitute for line in chart types such - # as Bar and Column that have a border and fill style rather than a line - # style. In general chart objects with a border property will also have a - # fill property. - # - # ===Fill - # - # The fill format is used to specify filled areas of chart objects such - # as the interior of a column or the background of the chart itself. - # - # The following properties can be set for fill formats in a chart. - # - # none - # color - # The none property is uses to turn the fill property off (it is - # generally on by default). - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :fill => { none => 1 } - # ) - # The color property sets the color of the fill area. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :fill => { color => 'red' } - # ) - # The available colors are shown in the main WriteXLSX documentation. - # It is also possible to set the color of a fill with a HTML style RGB color: - # - # chart.add_series( - # :fill => { color => '#FF0000' } - # ) - # The fill format is generally used in conjunction with a border format - # which has the same properties as a line format. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :border => { color => 'red' }, - # :fill => { color => 'yellow' } - # ) - # ===Marker - # - # The marker format specifies the properties of the markers used to - # distinguish series on a chart. In general only Line and Scatter - # chart types and trendlines use markers. - # - # The following properties can be set for marker formats in a chart. - # - # type - # size - # border - # fill - # The type property sets the type of marker that is used with a series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :marker => { type => 'diamond' } - # ) - # The following type properties can be set for marker formats in a chart. - # These are shown in the same order as in the Excel format dialog. - # - # automatic - # none - # square - # diamond - # triangle - # x - # star - # short_dash - # long_dash - # circle - # plus - # The automatic type is a special case which turns on a marker using the - # default marker style for the particular series number. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :marker => { type => 'automatic' } - # ) - # If automatic is on then other marker properties such as size, - # border or fill cannot be set. - # - # The size property sets the size of the marker and is generally used in - # conjunction with type. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :marker => { type => 'diamond', size => 7 } - # ) - # Nested border and fill properties can also be set for a marker. - # These have the same sub-properties as shown above. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :marker => { - # :type => 'square', - # :size => 5, - # :border => { color => 'red' }, - # :fill => { color => 'yellow' } - # } - # ) - # ===Trendline - # - # A trendline can be added to a chart series to indicate trends in the data - # such as a moving average or a polynomial fit. - # - # The following properties can be set for trendline formats in a chart. - # - # type - # order (for polynomial trends) - # period (for moving average) - # forward (for all except moving average) - # backward (for all except moving average) - # name - # line - # The type property sets the type of trendline in the series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { type => 'linear' } - # ) - # The available trendline types are: - # - # exponential - # linear - # log - # moving_average - # polynomial - # power - # A polynomial trendline can also specify the order of the polynomial. - # The default value is 2. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { - # :type => 'polynomial', - # :order => 3 - # } - # ) - # A moving_average trendline can also the period of the moving average. - # The default value is 2. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { - # :type => 'moving_average', - # :period => 3 - # } - # ) - # The forward and backward properties set the forecast period of the - # trendline. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { - # :type => 'linear', - # :forward => 0.5, - # :backward => 0.5 - # } - # ) - # The name property sets an optional name for the trendline that will - # appear in the chart legend. If it isn't specified the Excel default - # name will be displayed. This is usually a combination of the trendline - # type and the series name. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { - # :type => 'linear', - # :name => 'Interpolated trend' - # } - # ) - # Several of these properties can be set in one go: - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { - # :type => 'linear', - # :name => 'My trend name', - # :forward => 0.5, - # :backward => 0.5, - # :line => { - # :color => 'red', - # :width => 1, - # :dash_type => 'long_dash' - # } - # } - # ) - # Trendlines cannot be added to series in a stacked chart or pie chart or - # (when implemented) to 3-D, radar, surface, or doughnut charts. - # - # ==Data Labels - # - # Data labels can be added to a chart series to indicate the values of - # the plotted data points. - # - # The following properties can be set for data_labels formats in a chart. - # - # :value - # :category - # :series_name - # :position - # :leader_lines - # :percentage - # - # The value property turns on the Value data label for a series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :value => 1 } - # ) - # The category property turns on the Category Name data label for a series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :category => 1 } - # ) - # The series_name property turns on the Series Name data label for a series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :series_name => 1 } - # ) - # The C<position> property is used to position the data label for a series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :value => 1, :position => 'center' } - # ) - # - # Valid positions are: - # - # :center - # :right - # :left - # :top - # :bottom - # :above # Same as top - # :below # Same as bottom - # :inside_end # Pie chart mainly. - # :outside_end # Pie chart mainly. - # :best_fit # Pie chart mainly. - # - # The C<percentage> property is used to turn on the I<Percentage> - # for the data label for a series. It is mainly used for pie charts. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :percentage => 1 } - # ) - # - # The C<leader_lines> property is used to turn on I<Leader Lines> - # for the data label for a series. It is mainly used for pie charts. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :value => 1, :leader_lines => 1 } - # ) - # class Chart include Writexlsx::Utility attr_accessor :id, :name # :nodoc: attr_writer :index, :palette, :protection # :nodoc: @@ -558,14 +99,15 @@ @horiz_cat_axis = 0 @horiz_val_axis = 1 @protection = 0 @chartarea = {} @plotarea = {} - @x_axis = Axis.new - @y_axis = Axis.new - @x2_axis = Axis.new - @y2_axis = Axis.new + @title = Caption.new(self) + @x_axis = Axis.new(self) + @y_axis = Axis.new(self) + @x2_axis = Axis.new(self) + @y2_axis = Axis.new(self) @name = '' @show_blanks = 'gap' @show_hidden_data = false @show_crosses = true @width = 480 @@ -618,920 +160,100 @@ end # # Add a series and it's properties to a chart. # - # In an Excel chart a "series" is a collection of information such as - # values, x-axis labels and the formatting that define which data is - # plotted. - # - # With a WriteXLSX chart object the add_series() method is used to - # set the properties for a series: - # - # chart.add_series( - # :categories => '=Sheet1!$A$2:$A$10', # Optional. - # :values => '=Sheet1!$B$2:$B$10', # Required. - # :line => { :color => 'blue' } - # ) - # - # The properties that can be set are: - # - # ===:values - # This is the most important property of a series and must be set - # for every chart object. It links the chart with the worksheet data - # that it displays. A formula or array ref can be used for the - # data range, see below. - # - # ===:categories - # This sets the chart category labels. The category is more or less - # the same as the X-axis. In most chart types the categories property - # is optional and the chart will just assume a sequential series - # from 1 .. n. - # - # ===:name - # Set the name for the series. The name is displayed in the chart - # legend and in the formula bar. The name property is optional and - # if it isn't supplied it will default to Series 1 .. n. - # - # ===:line - # Set the properties of the series line type such as colour and - # width. See the "CHART FORMATTING" section below. - # - # ===:border - # Set the border properties of the series such as colour and style. - # See the "CHART FORMATTING" section below. - # - # ===:fill - # Set the fill properties of the series such as colour. See the - # "CHART FORMATTING" - # section below. - # - # ==:marker - # Set the properties of the series marker such as style and color. - # See the "CHART FORMATTING" section below. - # - # ===:trendline - # Set the properties of the series trendline such as linear, - # polynomial and moving average types. See the "CHART FORMATTING" - # section below. - # - # ===:data_labels - # Set data labels for the series. See the "CHART FORMATTING" - # section below. - # - # ===:invert_if_negative - # Invert the fill colour for negative values. Usually only applicable - # to column and bar charts. - # - # ===:overlap - # Set the overlap between series in a Bar/Column chart. The range is - # <tt>+/- 100</tt>. Default is 0. - # - # :overlap => 20 - # - # Note, it is only necessary to apply this property to one series of the chart. - # - # ===:gap - # Set the gap between series in a Bar/Column chart. The range is - # <tt>0 to 500</tt>. Default is 150. - # - # :gap => 200, - # - # Note, it is only necessary to apply this property to one series of the - # chart. - # - # The categories and values can take either a range formula such - # as <tt>=Sheet1!$A$2:$A$7</tt> or, more usefully when generating the range - # programmatically, an array ref with zero indexed row/column values: - # - # [ sheetname, row_start, row_end, col_start, col_end ] - # - # The following are equivalent: - # - # chart.add_series( categories => '=Sheet1!$A$2:$A$7' ) # Same as ... - # chart.add_series( categories => [ 'Sheet1', 1, 6, 0, 0 ] ) # Zero-indexed. - # - # You can add more than one series to a chart. In fact, some chart - # types such as stock require it. The series numbering and order in - # the Excel chart will be the same as the order in which that are added - # in WriteXLSX. - # - # # Add the first series. - # chart.add_series( - # :categories => '=Sheet1!$A$2:$A$7', - # :values => '=Sheet1!$B$2:$B$7', - # :name => 'Test data series 1' - # ) - # - # # Add another series. Same categories. Different range values. - # chart.add_series( - # :categories => '=Sheet1!$A$2:$A$7', - # :values => '=Sheet1!$C$2:$C$7', - # :name => 'Test data series 2' - # ) - # - # ==SERIES OPTIONS - # - # This section details the following properties of add_series() in more - # detail: - # - # marker - # trendline - # y_error_bars - # x_error_bars - # data_labels - # points - # - # ===Marker - # - # The marker format specifies the properties of the markers used to - # distinguish series on a chart. In general only Line and Scatter chart - # types and trendlines use markers. - # - # The following properties can be set for marker formats in a chart. - # - # type - # size - # border - # fill - # - # The type property sets the type of marker that is used with a series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :marker => { :type => 'diamond' } - # ) - # - # The following type properties can be set for marker formats in a chart. - # These are shown in the same order as in the Excel format dialog. - # - # automatic - # none - # square - # diamond - # triangle - # x - # star - # short_dash - # long_dash - # circle - # plus - # - # The automatic type is a special case which turns on a marker using the - # default marker style for the particular series number. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :marker => { :type => 'automatic' } - # ) - # - # If automatic is on then other marker properties such as size, border or - # fill cannot be set. - # - # The size property sets the size of the marker and is generally used in - # conjunction with type. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :marker => { :type => 'diamond', :size => 7 } - # ) - # - # Nested border and fill properties can also be set for a marker. See the - # "CHART FORMATTING" - # section below. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :marker => { - # :type => 'square', - # :size => 5, - # :border => { :color => 'red' }, - # :fill => { :color => 'yellow' } - # } - # ) - # - # ===Trendline - # - # A trendline can be added to a chart series to indicate trends in the data - # such as a moving average or a polynomial fit. - # - # The following properties can be set for trendlines in a chart series. - # - # type - # order (for polynomial trends) - # period (for moving average) - # forward (for all except moving average) - # backward (for all except moving average) - # name - # line - # - # The type property sets the type of trendline in the series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { :type => 'linear' } - # ) - # - # The available trendline types are: - # - # exponential - # linear - # log - # moving_average - # polynomial - # power - # - # A polynomial trendline can also specify the order of the polynomial. - # The default value is 2. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { - # :type => 'polynomial', - # :order => 3 - # } - # ) - # - # A moving_average trendline can also specify the period of the moving - # average. The default value is 2. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { - # :type => 'moving_average', - # :period => 3, - # } - # ) - # - # The forward and backward properties set the forecast period of the - # trendline. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { - # :type => 'linear', - # :forward => 0.5, - # :backward => 0.5 - # } - # ) - # - # The name property sets an optional name for the trendline that will - # appear in the chart legend. If it isn't specified the Excel default - # name will be displayed. This is usually a combination of the - # trendline type and the series name. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { - # :type => 'linear', - # :name => 'Interpolated trend' - # } - # ) - # - # Several of these properties can be set in one go: - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :trendline => { - # :type => 'linear', - # :name => 'My trend name', - # :forward => 0.5, - # :backward => 0.5, - # :line => { - # :color => 'red', - # :width => 1, - # :dash_type => 'long_dash' - # } - # } - # ) - # - # Trendlines cannot be added to series in a stacked chart or pie chart, - # radar chart or (when implemented) to 3D, surface, or doughnut charts. - # - # ===Error Bars - # - # Error bars can be added to a chart series to indicate error bounds in the - # data. The error bars can be vertical y_error_bars (the most common type) - # or horizontal x_error_bars (for Bar and Scatter charts only). - # - # The following properties can be set for error bars in a chart series. - # - # type - # value (for all types except standard error) - # direction - # end_style - # line - # - # The type property sets the type of error bars in the series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :y_error_bars => { :type => 'standard_error' } - # ) - # - # The available error bars types are available: - # - # fixed - # percentage - # standard_deviation - # standard_error - # - # Note, the "custom" error bars type is not supported. - # - # All error bar types, except for standard_error must also have a value - # associated with it for the error bounds: - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :y_error_bars => { - # :type => 'percentage', - # :value => 5 - # } - # ) - # - # The direction property sets the direction of the error bars. It should - # be one of the following: - # - # plus # Positive direction only. - # minus # Negative direction only. - # both # Plus and minus directions, The default. - # - # The end_style property sets the style of the error bar end cap. The - # options are 1 (the default) or 0 (for no end cap): - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :y_error_bars => { - # :type => 'fixed', - # :value => 2, - # :end_style => 0, - # :direction => 'minus' - # } - # ) - # - # ===Data Labels - # - # Data labels can be added to a chart series to indicate the values of the - # plotted data points. - # - # The following properties can be set for data_labels formats in a chart. - # - # value - # category - # series_name - # position - # leader_lines - # percentage - # - # The value property turns on the Value data label for a series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :value => 1 } - # ) - # The category property turns on the Category Name data label for a series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :category => 1 } - # ) - # - # The series_name property turns on the Series Name data label for a series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :series_name => 1 } - # ) - # - # The position property is used to position the data label for a series. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :value => 1, :position => 'center' }, - # ) - # - # Valid positions are: - # - # center - # right - # left - # top - # bottom - # above # Same as top - # below # Same as bottom - # inside_end # Pie chart mainly. - # outside_end # Pie chart mainly. - # best_fit # Pie chart mainly. - # - # The percentage property is used to turn on the display of data labels as - # a Percentage for a series. It is mainly used for pie charts. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :percentage => 1 } - # ) - # - # The leader_lines property is used to turn on Leader Lines for the data - # label for a series. It is mainly used for pie charts. - # - # chart.add_series( - # :values => '=Sheet1!$B$1:$B$5', - # :data_labels => { :value => 1, :leader_lines => 1 } - # ) - # - # Note: Even when leader lines are turned on they aren't automatically - # visible in Excel or Excel::Writer::XLSX. Due to an Excel limitation - # (or design) leader lines only appear if the data label is moved - # manually or if the data labels are very close and need to be adjusted - # automatically. - # - # ===Points - # - # In general formatting is applied to an entire series in a chart. However, - # it is occasionally required to format individual points in a series. In - # particular this is required for Pie charts where each segment is - # represented by a point. - # - # In these cases it is possible to use the points property of add_series(): - # - # chart.add_series( - # :values => '=Sheet1!$A$1:$A$3', - # :points => [ - # { :fill => { :color => '#FF0000' } }, - # { :fill => { ?color => '#CC0000' } }, - # { :fill => { :color => '#990000' } } - # ] - # ) - # - # The points property takes an array ref of format options (see the - # "CHART FORMATTING" - # section below). To assign default properties to points in a series pass - # nil values in the array ref: - # - # # Format point 3 of 3 only. - # chart.add_series( - # :values => '=Sheet1!$A$1:$A$3', - # :points => [ - # nil, - # nil, - # { :fill => { :color => '#990000' } } - # ] - # ) - # - # # Format the first point only. - # chart.add_series( - # :values => '=Sheet1!$A$1:$A$3', - # :points => [ { :fill => { :color => '#FF0000' } } ] - # ) def add_series(params) # Check that the required input has been specified. unless params.has_key?(:values) raise "Must specify ':values' in add_series" end if @requires_category != 0 && !params.has_key?(:categories) raise "Must specify ':categories' in add_series for this chart type" end - # Convert aref params into a formula string. - values = aref_to_formula(params[:values]) - categories = aref_to_formula(params[:categories]) + @series << Series.new(self, params) - # Switch name and name_formula parameters if required. - name, name_formula = process_names(params[:name], params[:name_formula]) - - # Get an id for the data equivalent to the range formula. - cat_id = get_data_id(categories, params[:categories_data]) - val_id = get_data_id(values, params[:values_data]) - name_id = get_data_id(name_formula, params[:name_data]) - - # Set the line properties for the series. - line = line_properties(params[:line]) - - # Allow 'border' as a synonym for 'line' in bar/column style charts. - line = line_properties(params[:border]) if params[:border] - - # Set the fill properties for the series. - fill = fill_properties(params[:fill]) - - # Set the marker properties for the series. - marker = marker_properties(params[:marker]) - - # Set the trendline properties for the series. - trendline = trendline_properties(params[:trendline]) - - # Set the line smooth property for the series. - smooth = params[:smooth] - - # Set the error bars properties for the series. - y_error_bars = error_bars_properties(params[:y_error_bars]) - x_error_bars = error_bars_properties(params[:x_error_bars]) - - # Set the point properties for the series. - points = points_properties(params[:points]) - - # Set the labels properties for the series. - labels = labels_properties(params[:data_labels]) - - # Set the "invert if negative" fill property. - invert_if_neg = params[:invert_if_negative] - - # Set the gap for Bar/Column charts. - if params[:gap] - @series_gap = params[:gap] - end - - # Set the overlap for Bar/Column charts. - if params[:overlap] - @series_overlap = params[:overlap] - end - - # Set the secondary axis properties. - x2_axis = params[:x2_axis] - y2_axis = params[:y2_axis] - - # Add the user supplied data to the internal structures. - @series << { - :_values => values, - :_categories => categories, - :_name => name, - :_name_formula => name_formula, - :_name_id => name_id, - :_val_data_id => val_id, - :_cat_data_id => cat_id, - :_line => line, - :_fill => fill, - :_marker => marker, - :_trendline => trendline, - :_smooth => smooth, - :_labels => labels, - :_invert_if_neg => invert_if_neg, - :_x2_axis => x2_axis, - :_y2_axis => y2_axis, - :_points => points, - :_error_bars => { - :_x_error_bars => x_error_bars, - :_y_error_bars => y_error_bars - } - } + # Set the gap and overlap for Bar/Column charts. + @series_gap = params[:gap] if params[:gap] + @series_overlap = params[:overlap] if params[:overlap] end # - # Set the properties of the X-axis. + # Set the properties of the x-axis. # - # The set_x_axis() method is used to set properties of the X axis. - # - # chart.set_x_axis( :name => 'Quarterly results' ) - # - # The properties that can be set are: - # - # :name - # :min - # :max - # :minor_unit - # :major_unit - # :crossing - # :reverse - # :log_base - # :label_position - # :major_gridlines - # :minor_gridlines - # :visible - # - # These are explained below. Some properties are only applicable to value - # or category axes, as indicated. See "Value and Category Axes" for an - # explanation of Excel's distinction between the axis types. - # - # ====:name - # Set the name (title or caption) for the axis. The name is displayed - # below the X axis. The name property is optional. The default is to - # have no axis name. (Applicable to category and value axes). - # - # chart.set_x_axis( :name => 'Quarterly results' ) - # - # The name can also be a formula such as =Sheet1!$A$1. - # - # ====:min - # Set the minimum value for the axis range. - # (Applicable to value axes only). - # - # chart.set_x_axis( :min => 20 ) - # ====:max - # Set the maximum value for the axis range. - # (Applicable to value axes only). - # - # chart.set_x_axis( :max => 80 ) - # ====:minor_unit - # Set the increment of the minor units in the axis range. - # (Applicable to value axes only). - # - # chart.set_x_axis( :minor_unit => 0.4 ) - # ====:major_unit - # Set the increment of the major units in the axis range. - # (Applicable to value axes only). - # - # chart.set_x_axis( :major_unit => 2 ) - # ====:crossing - # Set the position where the y axis will cross the x axis. - # (Applicable to category and value axes). - # - # The crossing value can either be the string 'max' to set the crossing - # at the maximum axis value or a numeric value. - # - # chart.set_x_axis( :crossing => 3 ) - # # or - # chart.set_x_axis( :crossing => 'max' ) - # For category axes the numeric value must be an integer to represent - # the category number that the axis crosses at. For value axes it can - # have any value associated with the axis. - # - # If crossing is omitted (the default) the crossing will be set - # automatically by Excel based on the chart data. - # - # ====:reverse - # Reverse the order of the axis categories or values. - # (Applicable to category and value axes). - # - # chart.set_x_axis( :reverse => 1 ) - # ====:log_base - # Set the log base of the axis range. - # (Applicable to value axes only). - # - # chart.set_x_axis( :log_base => 10 ) - # ====:label_position - # Set the "Axis labels" position for the axis. - # The following positions are available: - # - # next_to (the default) - # high - # low - # none - # More than one property can be set in a call to set_x_axis: - # - # chart.set_x_axis( - # :name => 'Quarterly results', - # :min => 10, - # :max => 80 - # ) - # - # ==CHART FONTS - # - # The following font properties can be set for any chart object that they - # apply to (and that are supported by WriteXLSX) such as chart titles, - # axis labels and axis numbering. They correspond to the equivalent - # Worksheet cell Format object properties. See "FORMAT_METHODS" for more - # information. - # - # name - # size - # bold - # italic - # underline - # rotation - # color - # - # The following explains the available font properties: - # - # ===name - # Set the font name: - # - # chart.set_x_axis( :num_font => { :name => 'Arial' } ) - # - # ===size - # Set the font size: - # - # chart.set_x_axis( :num_font => { :name => 'Arial', :size => 10 } ) - # - # ===bold - # Set the font bold property, should be 0 or 1: - # - # chart.set_x_axis( :num_font => { :bold => 1 } ) - # - # ===italic - # Set the font italic property, should be 0 or 1: - # - # chart.set_x_axis( :num_font => { :italic => 1 } ) - # - # ===underline - # Set the font underline property, should be 0 or 1: - # - # chart.set_x_axis( :num_font => { :underline => 1 } ) - # - # ===rotation - # See the font rotation in the range -90 to 90: - # - # chart.set_x_axis(:num_font => { :rotation => 45 }) - # - # This is useful for displaying large axis data such as dates in a more compact format. - # - # ===color - # Set the font color property. Can be a color index, a color name or HTML - # style RGB colour: - # - # chart.set_x_axis( :num_font => { :color => 'red' } ) - # chart.set_y_axis( :num_font => { :color => '#92D050' } ) - # - # Here is an example of Font formatting in a Chart program: - # - # # Format the chart title. - # chart.set_title( - # :name => 'Sales Results Chart', - # :name_font => { - # :name => 'Calibri', - # :color => 'yellow' - # } - # ) - # - # # Format the X-axis. - # chart.set_x_axis( - # :name => 'Month', - # :name_font => { - # :name => 'Arial', - # :color => '#92D050' - # }, - # :num_font => { - # :name => 'Courier New', - # :color => '#00B0F0' - # } - # ) - # - # # Format the Y-axis. - # chart.set_y_axis( - # :name => 'Sales (1000 units)', - # :name_font => { - # :name => 'Century', - # :underline => 1, - # :color => 'red' - # }, - # :num_font => { - # :bold => 1, - # :italic => 1, - # :color => '#7030A0' - # } - # ) def set_x_axis(params = {}) - @x_axis.merge_with_hash(self, params) + @x_axis.merge_with_hash(params) end # # Set the properties of the Y-axis. # # The set_y_axis() method is used to set properties of the Y axis. # The properties that can be set are the same as for set_x_axis, # def set_y_axis(params = {}) - @y_axis.merge_with_hash(self, params) + @y_axis.merge_with_hash(params) end # # Set the properties of the secondary X-axis. # def set_x2_axis(params = {}) - @x2_axis.merge_with_hash(self, params) + @x2_axis.merge_with_hash(params) end # # Set the properties of the secondary Y-axis. # def set_y2_axis(params = {}) - @y2_axis.merge_with_hash(self, params) + @y2_axis.merge_with_hash(params) end # # Set the properties of the chart title. # - # The set_title() method is used to set properties of the chart title. - # - # chart.set_title( :name => 'Year End Results' ) - # - # The properties that can be set are: - # - # ===:name - # Set the name (title) for the chart. The name is displayed above the - # chart. The name can also be a formula such as +=Sheet1!$A$1+. The name - # property is optional. The default is to have no chart title. - # - # ===:name_font - # Set the font properties for the chart title. See the "CHART FONTS" section. - # def set_title(params) - name, name_formula = process_names(params[:name], params[:name_formula]) - data_id = get_data_id(name_formula, params[:data]) - - @title_name = name - @title_formula = name_formula - @title_data_id = data_id - - # Set the font properties if present. - @title_font = convert_font_args(params[:name_font]) + @title.merge_with_hash(params) end # # Set the properties of the chart legend. # - # The set_legend() method is used to set properties of the chart legend. - # - # chart.set_legend( :position => 'none' ) - # - # The properties that can be set are: - # - # ===:position - # Set the position of the chart legend. - # - # chart.set_legend( :position => 'bottom' ) - # - # The default legend position is right. The available positions are: - # - # none - # top - # bottom - # left - # right - # overlay_left - # overlay_right - # - # ===:delete_series - # - # This allows you to remove 1 or more series from the the legend - # (the series will still display on the chart). This property takes - # an array ref as an argument and the series are zero indexed: - # - # # Delete/hide series index 0 and 2 from the legend. - # chart.set_legend(:delete_series => [0, 2]) - # def set_legend(params) @legend_position = params[:position] || 'right' @legend_delete_series = params[:delete_series] end # # Set the properties of the chart plotarea. # - # The set_plotarea() method is used to set properties of the plot area - # of a chart. - # - # This method isn't implemented yet and is only available in - # writeexcel gem. However, it can be simulated using the - # set_style() method. - # def set_plotarea(params) # Convert the user defined properties to internal properties. @plotarea = area_properties(params) end # # Set the properties of the chart chartarea. # - # The set_chartarea() method is used to set the properties of the chart - # area. - # - # chart.set_chartarea( - # :border => { :none => 1 }, - # :fill => { :color => 'red' } - # ) - # - # The properties that can be set are: - # ===:border - # Set the border properties of the chartarea such as colour and style. - # See the "CHART FORMATTING" section. - # ===:fill - # Set the fill properties of the plotarea such as colour. See the - # "CHART FORMATTING" section. - # def set_chartarea(params) # Convert the user defined properties to internal properties. @chartarea = area_properties(params) end # # Set on of the 42 built-in Excel chart styles. The default style is 2. # - # The set_style() method is used to set the style of the chart to one - # of the 42 built-in styles available on the 'Design' tab in Excel: - # - # chart.set_style( 4 ) - # - # The default style is 2. - # def set_style(style_id = 2) style_id = 2 if style_id < 0 || style_id > 42 @style_id = style_id end # # Set the option for displaying blank data in a chart. The default is 'gap'. # - # The show_blanks_as method controls how blank data is displayed in a chart. - # - # chart.show_blanks_as('span') - # - # The available options are: - # - # gap # Blank data is show as a gap. The default. - # zero # Blank data is displayed as zero. - # span # Blank data is connected with a line. - # def show_blanks_as(option) return unless option unless [:gap, :zero, :span].include?(option.to_sym) raise "Unknown show_blanks_as() option '#{option}'\n" @@ -1548,39 +270,10 @@ end # # Set dimensions for scale for the chart. # - # The set_size() method is used to set the dimensions of the chart. - # The size properties that can be set are: - # - # width - # height - # x_scale - # y_scale - # x_offset - # y_offset - # - # The width and height are in pixels. The default chart width is 480 - # pixels and the default height is 288 pixels. The size of the chart can - # be modified by setting the width and height or by setting the :x_scale - # and :y_scale: - # - # chart.set_size( :width => 720, :height => 576 ) - # - # # Same as: - # - # chart.set_size( :x_scale => 1.5, :y_scale => 2 ) - # - # The :x_offset and :y_offset position the top left corner of the chart - # in the cell that it is inserted into. - # - # Note: the :x_scale, :y_scale, :x_offset and :y_offset parameters can also - # be set via the insert_chart() method: - # - # worksheet.insert_chart( 'E2', chart, 2, 4, 1.5, 2 ) - # def set_size(params = {}) @width = params[:width] if params[:width] @height = params[:height] if params[:height] @x_scale = params[:x_scale] if params[:x_scale] @y_scale = params[:y_scale] if params[:y_scale] @@ -1593,42 +286,17 @@ # # The set_table method adds a data table below the horizontal axis with the # data used to plot the chart. # - # chart.set_table - # - # The available options, with default values are: - # - # :vertical => true # Display vertical lines in the table. - # :horizontal => true # Display horizontal lines in the table. - # :outline => true # Display an outline in the table. - # :show_keys => false # Show the legend keys with the table data. - # - # The data table can only be shown with Bar, Column, Line, Area and Stock charts. - # def set_table(params = {}) @table = Table.new(params) end # # Set properties for the chart up-down bars. # - # The set_up_down_bars() method adds Up-Down bars to Line charts to - # indicate the difference between the first and last data series. - # - # chart.set_up_down_bars - # It is possible to format the up and down bars to add fill and border - # properties if required. See the "CHART FORMATTING" section below. - # - # chart.set_up_down_bars( - # :up => { :fill => { :color => 'green' } }, - # :down => { :fill => { :color => 'red' } } - # ) - # Up-down bars can only be applied to Line charts and to Stock charts - # (by default). - # def set_up_down_bars(params = {}) # Map border to line. [:up, :down].each do |up_down| if params[up_down] params[up_down][:line] = params[up_down][:border] if params[up_down][:border] @@ -1651,44 +319,20 @@ end # # Set properties for the chart drop lines. # - # The set_drop_lines() method adds Drop Lines to charts to show the - # Category value of points in the data. - # - # chart.set_drop_lines - # - # It is possible to format the Drop Line line properties if required. - # See the "CHART FORMATTING" section below. - # - # chart.set_drop_lines(:line => { :color => 'red', :dash_type => 'square_dot' } ) - # - # Drop Lines are only available in Line, Area and Stock charts. - # def set_drop_lines(params = {}) # Set the drop line properties. line = line_properties(params[:line]) @drop_lines = { :_line => line } end # # Set properties for the chart high-low lines. # - # The set_high_low_lines() method adds High-Low lines to charts to show - # the maximum and minimum values of points in a Category. - # - # chart.set_high_low_lines - # - # It is possible to format the High-Low Line line properties if required. - # See the "CHART FORMATTING" section below. - # - # chart.set_high_low_lines( :line => { :color => 'red' } ) - # - # High-Low Lines are only available in Line and Stock charts. - # def set_high_low_lines(params = {}) # Set the drop line properties. line = line_properties(params[:line]) @hi_low_lines = { :_line => line } @@ -1741,57 +385,10 @@ write_axis_ids(params) end end # - # Switch name and name_formula parameters if required. - # - def process_names(name = nil, name_formula = nil) # :nodoc: - # Name looks like a formula, use it to set name_formula. - if name && name =~ /^=[^!]+!\$/ - name_formula = name - name = '' - end - - [name, name_formula] - end - - # - # Assign an id to a each unique series formula or title/axis formula. Repeated - # formulas such as for categories get the same id. If the series or title - # has user specified data associated with it then that is also stored. This - # data is used to populate cached Excel data when creating a chart. - # If there is no user defined data then it will be populated by the parent - # workbook in Workbook::_add_chart_data - # - def get_data_id(formula, data) # :nodoc: - # Ignore series without a range formula. - return unless formula - - # Strip the leading '=' from the formula. - formula = formula.sub(/^=/, '') - - # Store the data id in a hash keyed by the formula and store the data - # in a separate array with the same id. - if !@formula_ids.has_key?(formula) - # Haven't seen this formula before. - id = @formula_data.size - - @formula_data << data - @formula_ids[formula] = id - else - # Formula already seen. Return existing id. - id = @formula_ids[formula] - - # Store user defined data if it isn't already there. - @formula_data[id] = data unless @formula_data[id] - end - - id - end - - # # Convert user defined font values into private hash values. # def convert_font_args(params) return unless params font = { @@ -1848,10 +445,57 @@ line[:_defined] = 1 line end + # + # Switch name and name_formula parameters if required. + # + def process_names(name = nil, name_formula = nil) # :nodoc: + # Name looks like a formula, use it to set name_formula. + if name && name =~ /^=[^!]+!\$/ + name_formula = name + name = '' + end + + [name, name_formula] + end + + # + # Assign an id to a each unique series formula or title/axis formula. Repeated + # formulas such as for categories get the same id. If the series or title + # has user specified data associated with it then that is also stored. This + # data is used to populate cached Excel data when creating a chart. + # If there is no user defined data then it will be populated by the parent + # workbook in Workbook::_add_chart_data + # + def get_data_id(formula, data) # :nodoc: + # Ignore series without a range formula. + return unless formula + + # Strip the leading '=' from the formula. + formula = formula.sub(/^=/, '') + + # Store the data id in a hash keyed by the formula and store the data + # in a separate array with the same id. + if !@formula_ids.has_key?(formula) + # Haven't seen this formula before. + id = @formula_data.size + + @formula_data << data + @formula_ids[formula] = id + else + # Formula already seen. Return existing id. + id = @formula_ids[formula] + + # Store user defined data if it isn't already there. + @formula_data[id] = data unless @formula_data[id] + end + + id + end + private # # retun primary/secondary series by :primary_axes flag # @@ -1862,19 +506,10 @@ secondary_axes_series end end # - # Convert and aref of row col values to a range formula. - # - def aref_to_formula(data) # :nodoc: - # If it isn't an array ref it is probably a formula already. - return data unless data.kind_of?(Array) - xl_range_formula(*data) - end - - # # Find the overall type of the data associated with a series. # # TODO. Need to handle date type. # def get_data_type(data) # :nodoc: @@ -1992,179 +627,10 @@ fill end # - # Convert user defined marker properties to the structure required internally. - # - def marker_properties(marker) # :nodoc: - return unless marker - - types = { - :automatic => 'automatic', - :none => 'none', - :square => 'square', - :diamond => 'diamond', - :triangle => 'triangle', - :x => 'x', - :star => 'start', - :dot => 'dot', - :short_dash => 'dot', - :dash => 'dash', - :long_dash => 'dash', - :circle => 'circle', - :plus => 'plus', - :picture => 'picture' - } - - # Check for valid types. - marker_type = marker[:type] - - if marker_type - marker[:automatic] = 1 if marker_type == 'automatic' - marker[:type] = value_or_raise(types, marker_type, 'maker type') - end - - # Set the line properties for the marker.. - line = line_properties(marker[:line]) - - # Allow 'border' as a synonym for 'line'. - line = line_properties(marker[:border]) if marker[:border] - - # Set the fill properties for the marker. - fill = fill_properties(marker[:fill]) - - marker[:_line] = line - marker[:_fill] = fill - - marker - end - - # - # Convert user defined trendline properties to the structure required internally. - # - def trendline_properties(trendline) # :nodoc: - return unless trendline - - types = { - :exponential => 'exp', - :linear => 'linear', - :log => 'log', - :moving_average => 'movingAvg', - :polynomial => 'poly', - :power => 'power' - } - - # Check the trendline type. - trend_type = trendline[:type] - - trendline[:type] = value_or_raise(types, trend_type, 'trendline type') - - # Set the line properties for the trendline.. - line = line_properties(trendline[:line]) - - # Allow 'border' as a synonym for 'line'. - line = line_properties(trendline[:border]) if trendline[:border] - - # Set the fill properties for the trendline. - fill = fill_properties(trendline[:fill]) - - trendline[:_line] = line - trendline[:_fill] = fill - - return trendline - end - - # - # Convert user defined error bars properties to structure required - # internally. - # - def error_bars_properties(params = {}) - return if !ptrue?(params) || params.empty? - - # Default values. - error_bars = { - :_type => 'fixedVal', - :_value => 1, - :_endcap => 1, - :_direction => 'both' - } - - types = { - :fixed => 'fixedVal', - :percentage => 'percentage', - :standard_deviation => 'stdDev', - :standard_error => 'stdErr' - } - - # Check the error bars type. - error_type = params[:type].to_sym - - if types.key?(error_type) - error_bars[:_type] = types[error_type] - else - raise "Unknown error bars type '#{error_type}'\n" - end - - # Set the value for error types that require it. - if params.key?(:value) - error_bars[:_value] = params[:value] - end - - # Set the end-cap style. - if params.key?(:end_style) - error_bars[:_endcap] = params[:end_style] - end - - # Set the error bar direction. - if params.key?(:direction) - if params[:direction] == 'minus' - error_bars[:_direction] = 'minus' - elsif params[:direction] == 'plus' - error_bars[:_direction] = 'plus' - else - # Default to 'both' - end - end - - # Set the line properties for the error bars. - error_bars[:_line] = line_properties(params[:line]) - - error_bars - end - - # - # Convert user defined labels properties to the structure required internally. - # - def labels_properties(labels) # :nodoc: - return nil unless labels - - position = labels[:position] - if position.nil? || position.empty? - labels.delete(:position) - else - # Map user defined label positions to Excel positions. - positions = { - :center => 'ctr', - :right => 'r', - :left => 'l', - :top => 't', - :above => 't', - :bottom => 'b', - :below => 'b', - :inside_end => 'inEnd', - :outside_end => 'outEnd', - :best_fit => 'bestFit' - } - - labels[:position] = value_or_raise(positions, position, 'label position') - end - - labels - end - - # # Convert user defined area properties to the structure required internally. # def area_properties(arg) # :nodoc: area = {} @@ -2205,75 +671,50 @@ area[:_fill] = fill return area end - # - # Convert user defined points properties to structure required internally. - # - def points_properties(user_points = nil) - return unless user_points - - points = [] - user_points.each do |user_point| - if user_point - # Set the lline properties for the point. - line = line_properties(user_point[:line]) - - # Allow 'border' as a synonym for 'line'. - if user_point[:border] - line = line_properties(user_point[:border]) - end - - # Set the fill properties for the chartarea. - fill = fill_properties(user_point[:fill]) - - point = {} - point[:_line] = line - point[:_fill] = fill - end - points << point - end - points - end - def value_or_raise(hash, key, msg) raise "Unknown #{msg} '#{key}'" unless hash[key.to_sym] hash[key.to_sym] end # # Returns series which use the primary axes. # def get_primary_axes_series - @series.reject {|s| s[:_y2_axis]} + @series.reject {|s| s.y2_axis} end alias :primary_axes_series :get_primary_axes_series # # Returns series which use the secondary axes. # def get_secondary_axes_series - @series.select {|s| s[:_y2_axis]} + @series.select {|s| s.y2_axis} end alias :secondary_axes_series :get_secondary_axes_series # # Add a unique ids for primary or secondary axis. # def add_axis_ids(params) # :nodoc: + if ptrue?(params[:primary_axes]) + @axis_ids += ids + else + @axis2_ids += ids + end + end + + def ids chart_id = 1 + @id axis_count = 1 + @axis2_ids.size + @axis_ids.size id1 = sprintf('5%03d%04d', chart_id, axis_count) id2 = sprintf('5%03d%04d', chart_id, axis_count + 1) - if ptrue?(params[:primary_axes]) - @axis_ids << id1 << id2 - else - @axis2_ids << id1 << id2 - end + [id1, id2] end # # Get the font style attributes from a font hash. # @@ -2424,14 +865,14 @@ # Write the <c:chart> element. # def write_chart # :nodoc: @writer.tag_elements('c:chart') do # Write the chart title elements. - if title = @title_formula - write_title_formula(title, @title_data_id, nil, @title_font) - elsif title = @title_name - write_title_rich(title, nil, @title_font) + if @title.formula + write_title_formula(@title, nil) + elsif @title.name + write_title_rich(@title, nil) end # Write the c:plotArea element. write_plot_area # Write the c:legend element. @@ -2529,34 +970,10 @@ # def write_series(series) # :nodoc: write_ser(series) end - def write_series_base - # Write each series with subelements. - index = 0 - @series.each do |series| - write_ser(index, series) - index += 1 - end - - # Write the c:marker element. - write_marker_value - - # Write the c:overlap element - # block given by Bar and Column - yield - - # Generate the axis ids. - add_axis_id - add_axis_id - - # Write the c:axId element. - write_axis_id(@axis_ids[0]) - write_axis_id(@axis_ids[1]) - end - # # Write the <c:ser> element. # def write_ser(series) # :nodoc: index = @series_index @@ -2570,27 +987,27 @@ # Write the series name. write_series_name(series) # Write the c:spPr element. write_sp_pr(series) # Write the c:marker element. - write_marker(series[:_marker]) + write_marker(series.marker) # Write the c:invertIfNegative element. - write_c_invert_if_negative(series[:_invert_if_neg]) + write_c_invert_if_negative(series.invert_if_neg) # Write the c:dPt element. - write_d_pt(series[:_points]) + write_d_pt(series.points) # Write the c:dLbls element. - write_d_lbls(series[:_labels]) + write_d_lbls(series.labels) # Write the c:trendline element. - write_trendline(series[:_trendline]) + write_trendline(series.trendline) # Write the c:errBars element. - write_error_bars(series[:_error_bars]) + write_error_bars(series.error_bars) # Write the c:cat element. write_cat(series) # Write the c:val element. write_val(series) # Write the c:smooth element. - write_c_smooth(series[:_smooth]) if ptrue?(@smooth_allowed) + write_c_smooth(series.smooth) if ptrue?(@smooth_allowed) end end # # Write the <c:idx> element. @@ -2608,24 +1025,24 @@ # # Write the series name. # def write_series_name(series) # :nodoc: - if name = series[:_name_formula] - write_tx_formula(name, series[:_name_id]) - elsif name = series[:_name] - write_tx_value(name) + if series.name_formula + write_tx_formula(series.name_formula, series.name_id) + elsif series.name + write_tx_value(series.name) end end # # Write the <c:cat> element. # def write_cat(series) # :nodoc: - formula = series[:_categories] - data_id = series[:_cat_data_id] + formula = series.categories + data_id = series.cat_data_id data = @formula_data[data_id] if data_id # Ignore <c:cat> elements for charts without category values. return unless formula @@ -2647,11 +1064,11 @@ # # Write the <c:val> element. # def write_val(series) # :nodoc: - write_val_base(series[:_values], series[:_val_data_id], 'c:val') + write_val_base(series.values, series.val_data_id, 'c:val') end def write_val_base(formula, data_id, tag) # :nodoc: data = @formula_data[data_id] @@ -2762,14 +1179,14 @@ # Write the c:minorGridlines element. write_minor_gridlines(x_axis.minor_gridlines) # Write the axis title elements. - if title = x_axis.formula - write_title_formula(title, @x_axis.data_id, horiz, @x_axis.name_font) - elsif title = x_axis.name - write_title_rich(title, horiz, x_axis.name_font) + if x_axis.formula + write_title_formula(x_axis, horiz, @x_axis) + elsif x_axis.name + write_title_rich(x_axis, horiz) end # Write the c:numFmt element. write_cat_number_format(x_axis) @@ -2830,14 +1247,14 @@ # Write the c:minorGridlines element. write_minor_gridlines(y_axis.minor_gridlines) # Write the axis title elements. - if title = y_axis.formula - write_title_formula(title, y_axis.data_id, horiz, y_axis.name_font) - elsif title = y_axis.name - write_title_rich(title, horiz, y_axis.name_font) + if y_axis.formula + write_title_formula(y_axis, horiz) + elsif y_axis.name + write_title_rich(y_axis, horiz) end # Write the c:numberFormat element. write_number_format(y_axis) @@ -2900,14 +1317,14 @@ # Write the c:minorGridlines element. write_minor_gridlines(x_axis.minor_gridlines) # Write the axis title elements. - if title = x_axis.formula - write_title_formula(title, y_axis.data_id, horiz, x_axis.name_font) - elsif title = x_axis.name - write_title_rich(title, horiz, x_axis.name_font) + if x_axis.formula + write_title_formula(x_axis, horiz) + elsif x_axis.name + write_title_rich(x_axis, horiz) end # Write the c:numberFormat element. write_number_format(x_axis) @@ -2966,14 +1383,14 @@ # Write the c:minorGridlines element. write_minor_gridlines(x_axis.minor_gridlines) # Write the axis title elements. - if title = x_axis.formula - write_title_formula(title, x_axis.data_id, nil, x_axis.name_font) - elsif title = x_axis.name - write_title_rich(title, nil, x_axis.name_font) + if x_axis.formula + write_title_formula(x_axis, nil) + elsif x_axis.name + write_title_rich(x_axis, nil) end # Write the c:numFmt element. write_number_format(x_axis) # Write the c:majorTickMark element. write_major_tick_mark(x_axis.major_tick_mark) @@ -3369,38 +1786,38 @@ end # # Write the <c:title> element for a rich string. # - def write_title_rich(title, horiz = nil, font = nil) # :nodoc: + def write_title_rich(title, horiz = nil) # :nodoc: @writer.tag_elements('c:title') do # Write the c:tx element. - write_tx_rich(title, horiz, font) + write_tx_rich(title, horiz) # Write the c:layout element. write_layout end end # # Write the <c:title> element for a rich string. # - def write_title_formula(title, data_id, horiz = nil, font = nil) # :nodoc: + def write_title_formula(title, horiz = nil, axis = nil) # :nodoc: @writer.tag_elements('c:title') do # Write the c:tx element. - write_tx_formula(title, data_id) + write_tx_formula(title.formula, axis ? axis.data_id : title.data_id) # Write the c:layout element. write_layout # Write the c:txPr element. - write_tx_pr(horiz, font) + write_tx_pr(horiz, axis ? axis.name_font : title.name_font) end end # # Write the <c:tx> element. # - def write_tx_rich(title, horiz, font = nil) # :nodoc: - @writer.tag_elements('c:tx') { write_rich(title, horiz, font) } + def write_tx_rich(title, horiz) # :nodoc: + @writer.tag_elements('c:tx') { write_rich(title, horiz) } end # # Write the <c:tx> element with a simple value such as for series names. # @@ -3418,18 +1835,18 @@ end # # Write the <c:rich> element. # - def write_rich(title, horiz, font) # :nodoc: + def write_rich(title, horiz) # :nodoc: @writer.tag_elements('c:rich') do # Write the a:bodyPr element. write_a_body_pr(horiz) # Write the a:lstStyle element. write_a_lst_style # Write the a:p element. - write_a_p_rich(title, font) + write_a_p_rich(title) end end # # Write the <a:bodyPr> element. @@ -3468,16 +1885,16 @@ end # # Write the <a:p> element for rich string titles. # - def write_a_p_rich(title, font) # :nodoc: + def write_a_p_rich(title) # :nodoc: @writer.tag_elements('a:p') do # Write the a:pPr element. - write_a_p_pr_rich(font) + write_a_p_pr_rich(title.name_font) # Write the a:r element. - write_a_r(title, font) + write_a_r(title) end end # # Write the <a:p> element for formula titles. @@ -3523,16 +1940,16 @@ end # # Write the <a:r> element. # - def write_a_r(title, font) # :nodoc: + def write_a_r(title) # :nodoc: @writer.tag_elements('a:r') do # Write the a:rPr element. - write_a_r_pr(font) + write_a_r_pr(title.name_font) # Write the a:t element. - write_a_t(title) + write_a_t(title.name) end end # # Write the <a:rPr> element. @@ -3629,25 +2046,28 @@ # # Write the <c:spPr> element. # def write_sp_pr(series) # :nodoc: - return if (!series.has_key?(:_line) || !ptrue?(series[:_line][:_defined])) && - (!series.has_key?(:_fill) || !ptrue?(series[:_fill][:_defined])) + line = series.respond_to?(:line) ? series.line : series[:_line] + fill = series.respond_to?(:fill) ? series.fill : series[:_fill] + return if (!line || !ptrue?(line[:_defined])) && + (!fill || !ptrue?(fill[:_defined])) + @writer.tag_elements('c:spPr') do # Write the fill elements for solid charts such as pie and bar. - if series[:_fill] && series[:_fill][:_defined] != 0 - if ptrue?(series[:_fill][:none]) + if fill && fill[:_defined] != 0 + if ptrue?(fill[:none]) # Write the a:noFill element. write_a_no_fill else # Write the a:solidFill element. - write_a_solid_fill(series[:_fill]) + write_a_solid_fill(fill) end end # Write the a:ln element. - write_a_ln(series[:_line]) if series[:_line] && ptrue?(series[:_line][:_defined]) + write_a_ln(line) if line && ptrue?(line[:_defined]) end end # # Write the <a:ln> element.