in reply to Re: Excel macro to perl conversion.
in thread Excel macro to perl conversion.

Hi Grygonos, thanks for the help. I tried to use your code to generate a chart instead, but had no luck. I find this OLE stuff very tricky!

I am trying to graph some data. The easiest way to show you what I'm trying to do is to show you the spreadsheet, have a look at the picture on my home node.

To make life easier, I created a template spreadsheet, which I open and insert the data into. (Although I would prefer not to use a template, and create the entire spreadsheet on the fly.) The problem occurs when the data range does not match the range in the template. Say I designed the graph to cope with 31 days worth of data, and the user only wants to plot 7 days worth of data. What happens is that the 1st 6 days of data occupy the same area as the fisrt 6 days of 31 days worth of data.

So, I started a macro, and changed the data range of the chart to match the data, and it cured the problem. However, when I tried to convert the macro so I could do this from perl, it didn't work.

The macro looked like this:

Sub Macro1() Sheets("Graph").Select ActiveSheet.ChartObjects("Chart 1").Activate ActiveChart.SeriesCollection(1).Select ActiveChart.SetSourceData Source:=Sheets("Data").Range("A1:C49"), +PlotBy:= _ xlColumns End Sub
From this macro, I produced this script. It doesn't work as expected though. If you un-comment the '$chart -> delete();' line, the chart does get deleted, so I know I've got the chart, but the marked line causes an error, and the data range doesn't get changed.
use strict; use warnings; use Win32::OLE qw(in with); use Win32::OLE::Const 'Microsoft Excel'; use Win32::OLE::Variant; use Win32::OLE::NLS qw(:LOCALE :DATE); $Win32::OLE::Warn = 0; my $template = "D:/My Scripts/test_chart.xls"; my $outexcel = "D:/My Scripts/test_chart1.xls"; my $excel; eval {$excel = Win32::OLE->GetActiveObject('Excel.Application')}; die "WARNING! Excel not installed" if $@; unless (defined $excel) { $excel = Win32::OLE->new('Excel.Application', sub {$_[0]->Quit;}) +or die "ERROR, cannot start Excel"; } $excel -> {Visible} = 1; $excel->{DisplayAlerts} = 0; die "Cannot find template $template\n" unless (-e $template); my $workbook = $excel -> Workbooks -> Open($template); my $range = "A1:C49"; my $sheet = $workbook -> Worksheets("Graph"); $sheet -> Activate(); my $chart = $sheet -> ChartObjects("Chart 1"); $chart -> Activate(); my $collection = $chart -> SeriesCollection(1); $collection -> Select(); # Can't call method "Select" on an undefined +value $chart->SetSourceData({Source => "$sheet", Range => "$range", PlotBy = +> "xlColumns"}); # $chart -> delete(); #This will work! # save the spreadsheet $workbook->SaveAs($outexcel); undef $workbook; undef $excel; exit();
The data is on sheet2 (named "Data") and occupies a range of A2:C745, if there is a full month's worth. The headings for the columns are in A1:C1.

On sheet1, called "Chart" is a chart of this data. I have put a picture of these sheets on my home node.

Replies are listed 'Best First'.
Re^3: Excel macro to perl conversion.
by Grygonos (Chaplain) on Oct 15, 2004 at 13:12 UTC

    That is expected that the series collection would cause a problem. If you have no current series in the graph you have to add one before you can do anythin with it, as I did in my code above. I would also reccomend generating your template on the fly (oxymoronic I know!)and not relying on a file already present.

      Thanks for the help, guys. I have finally sussed it!

      I recorded this macro while creating the chart:

      Range("C1:C721").Select Charts.Add ActiveChart.ChartType = xlLine ActiveChart.SetSourceData Source:=Sheets("Data").Range("A1:C721"), + PlotBy:= _ xlColumns ActiveChart.SeriesCollection(1).XValues = "=Data!R2C1:R721C2" ActiveChart.Location Where:=xlLocationAsNewSheet ActiveChart.HasLegend = False ActiveChart.HasDataTable = False ActiveChart.Axes(xlCategory).Select With Selection.Border .Weight = xlHairline .LineStyle = xlAutomatic End With With Selection .MajorTickMark = xlNone .MinorTickMark = xlNone .TickLabelPosition = xlNextToAxis End With Selection.TickLabels.AutoScaleFont = True With Selection.TickLabels.Font .Name = "Arial" .FontStyle = "Regular" .Size = 8 .Strikethrough = False .Superscript = False .Subscript = False .OutlineFont = False .Shadow = False .Underline = xlUnderlineStyleNone .ColorIndex = xlAutomatic .Background = xlAutomatic End With Selection.TickLabels.AutoScaleFont = True With Selection.TickLabels.Font .Name = "Arial" .FontStyle = "Regular" .Size = 5 .Strikethrough = False .Superscript = False .Subscript = False .OutlineFont = False .Shadow = False .Underline = xlUnderlineStyleNone .ColorIndex = xlAutomatic .Background = xlAutomatic End With
      And it converted to this code:
      $sheet->Range("C1:C721")->Select; my $chart = $workbook->Charts->Add; $chart->{Name} = "Chart"; $chart->{ChartType} = xlLine; $chart->SeriesCollection(1)->{XValues} = "=Data!R2C1:R721C2"; $chart->Location(xlLocationAsNewSheet); $chart = $excel->ActiveChart; $chart->{HasLegend} = "False; $chart->Axes(xlCategory)->{MajorTickMark} = xlNone; $chart->Axes(xlCategory)->{TickLabels}{Font}{Size} = 5;
      See my home node for a picture of the chart and data, if you like. Ooh! and if anyone's looking for a meaty project, how about a script to automatically convert an Excel macro into perl? That's be nice! ;-)