in reply to Excel macro to perl conversion.

your variable $chart is not being populated. do  print $chart; after you try to set it.. it should print out an ole hash ref... if it doesn't then you know you didn't get the reference assigned correctly. Are you sure "Chart 1" is the name.. or that it even exists at this point since it seems you are trying to edit a chart?

Well, since I don't know exactly what this code is trying to do on a larger level (i.e. edit an old series or make a new one) I can only provide this example of working code from one of my scripts that uses graphs

#Create embedded chart objects my $production_chart = $sheet->ChartObjects->Add(25,250,300,160); my $performance_chart = $sheet->ChartObjects->Add(350,250,300,160) +; #Set the Chart Type $performance_chart->Chart->{ChartType} = $$xlConst{'xlLine'}; $production_chart->Chart->{ChartType} = $$xlConst{'xlLine'}; #Create the series $production_chart->Chart->SeriesCollection->Add($sheet->Range($_." +4:".$_."16"), $$xlConst{'xlColum +ns'}, TRUE) for(qw(E F G + H)); #Create the series $performance_chart->Chart->SeriesCollection->Add($sheet->Range($_. +"4:".$_."16"), $$xlConst{'xlColu +mns'}, TRUE) for(qw(I J) +); #Color the background of the charts $performance_chart->Chart->PlotArea->Interior->{ColorIndex} = 0; $production_chart->Chart->PlotArea->Interior->{ColorIndex} = 0;
This code creates two charts via the add method of chartobjects. It then sets the type of the chart object, and then adds a set of series to each of them, and sets their background colors. I hope this helps. If you edit and post the whole intent of the code I may be able to help more

Replies are listed 'Best First'.
Re^2: Excel macro to perl conversion.
by spikey_wan (Scribe) on Oct 15, 2004 at 09:52 UTC
    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.

      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! ;-)