Can't draw lines in GooCanvas - perl

In a Perl/Gtk3 script and using GooCanvas, I can easily draw a rectangle, or an ellipsis, or whatever, but it seems to be impossible to draw a simple line.
Lines are drawn with a call to Goo::CanvasPolyline->new(). The line's coordinates a specified by a call to Goo::CanvasPoints->new(), but that call creates the following error:
GLib-ERROR **: ../../../../glib/gmem.c:105: failed to allocate 18446744069314558208 bytes at /usr/lib/x86_64-linux-gnu/perl5/5.26/Glib/Object/Introspection.pm line 67.
Aborted (core dumped)
I've tried the Perl module Goo::Canvas and the more modern GooCanvas2; both produce the same error.
I wasn't able to find any working code examples; merely the non-working script below, which Google found on $RANDOM_WEBSITE.
#!/usr/bin/perl -w
use strict;
use warnings;
use Gtk3 -init;
Glib::Object::Introspection->setup(basename => 'GooCanvas', version => '2.0', package => 'Goo');
my $window = Gtk3::Window->new('toplevel');
$window->signal_connect('delete_event' => sub { Gtk2->main_quit; });
$window->set_size_request(640, 600);
$window->set_title("Gtk3 GooCanvas with Perl Gobject Introspection");
$window->signal_connect(destroy => sub { Gtk3->main_quit });
my $swin = Gtk3::ScrolledWindow->new;
$swin->set_shadow_type('in');
$window->add($swin);
my $canvas = Goo::Canvas->new; # Gobject Introspection of Gtk3 Goo version
$canvas->set_size_request(800, 650);
$canvas->set_bounds(0, 0, 1000, 1000);
$swin->add($canvas);
my $root = $canvas->get_root_item();
# first point set
my $pts_ref = [50,50,180,120,90,100,50,50];
my $points = Goo::CanvasPoints->new(
$pts_ref,
);
my $line = Goo::CanvasPolyline->new(
'parent' => $root,
'close-path' => 0,
'points' => $points, #in Gtk2 could just use $pts_ref
'stroke-color' => 'black',
'line-width' => 3,
);
my $ellipse = Goo::CanvasEllipse->new(
'parent' => $root,
'center-x' => 20,
'center-y' => 20,
'width' => +60,
'height' => +60,
'stroke-color' => 'goldenrod',
'line-width' => 8,
'fill-color-rgba' => 0x3cb37180,
);
$root->translate(200,200);
$window->show_all();
Gtk3->main;
__END__

my $points = Goo::CanvasPoints->new( $pts_ref );
According to the documentation the constructor should take the number of points to reserve, not the reference to the points array. So you could try:
[...]
# first point set
my $pts_ref = [50,50,180,120,90,100,50,50];
my $num_points = (scalar #$pts_ref)/2;
my $points = Goo::CanvasPoints->new( $num_points );
# Set the points:
my $j = 0;
for my $i (0..($num_points -1)) {
my $x = $pts_ref->[$j];
my $y = $pts_ref->[$j+1];
$points->set_point($i, $x, $y);
$j += 2;
}
[...]

Related

How to get "Var1" value of dumper in perl

When i use below code then it gives output, But i want "width", "file_media_type", "file_ext" values, But I am unable to get this value in individual. I am very new with Perl Please help me!
Code
use warnings ;
use strict;
use Image::Info qw[image_info];
use Data::Dumper;
my $file = 'd:\perl\test\a.jpg';
my $info = Dumper(image_info($file));
print $info;
Output
$VAR1 = {
'width' => 45,
'file_media_type' => 'image/png',
'file_ext' => 'png',
'PNG_Chunks' => [
'IHDR',
'gAMA',
'cHRM',
'IDAT',
'IEND'
],
'Chunk-cHRM' => ' z% Çâ ·  ÇF u0 O` :ù ?o',
'PNG_Filter' => 'Adaptive',
'color_type' => 'RGB',
'height' => 20,
'Gamma' => '0.45454',
'resolution' => '1/1',
'SampleFormat' => 'U8',
'Compression' => 'Deflate'
};
image_info($file) returns a hash reference. Looking at the dump you know the keys available (the keys are strings before =>)
$info = image_info($file);
foreach my $key ( qw/width file_media_type file_ext/ ){
print "$key:$info->{$key}\n";
}

BioPerl/BioGraphics only prints one value instead of all

I am trying to plot SNPs onto a gene (or below). The code I have is the following:
#!/usr/bin/perl
use strict;
use warnings;
use Bio::Graphics;
use Bio::SeqFeature::Generic;
my #SNPs = "408777 408900 409100 409480";
my $gene_name = "GSTd10";
my $scaffold = "KB668289";
my $gene_start = 408763;
my $gene_end = 409489;
my $length = $gene_end - $gene_start + 50;
open my $png, ">", "$gene_name.png" or die "Cannot open $gene_name.png: $!\n";
#Create a panel for the image#
my $panel=Bio::Graphics::Panel->new(-offset => $gene_start, -length => $length, -width => 1000, -pad_left => 100, -pad_right => 10, -pad_top => 10);
my $track_whole=$panel->add_track(-glyph => 'graded_segments', -label => 1, -bgcolor => 'black', -font2color => 'black',);
my $feature= Bio::SeqFeature::Generic->new(-display_name => $gene_name, -start => $gene_start, -end => $gene_end,);
$track_whole->add_feature($feature);
my $track=$panel->add_track(-glyph => 'graded_segments', -label => 1, -bgcolor =>'blue', -min_score => 0, -max_score => 30, -font2color => 'black');
foreach my $SNP (#SNPs)
{
my $feature= Bio::SeqFeature::Generic->new(-label => $SNP, -start => $SNP, -end => $SNP);
$track->add_feature($feature);
}
#This will print out the final panel i.e. you must have created an object called $panel above
print $png $panel -> png;
Whenever I run this script, I only get printed one line.
Where is the mistake in order to print all values in #SNPs? In addition, is there a way of printing ^ instead of a block?
In this line
my #SNPs = "408777 408900 409100 409480";
You're just creating an array with a single element of that whole string.
Try
my #SNPs = qw(408777 408900 409100 409480);

bioperl package Bio::Tree::Tree can't locate object method as_text

I'm trying to use as_text method from Bio::Tree::Tree I get this message: can't locate object method as_text via package Bio::Tree::Tree
I'm using the example here
Note that I tried other methods in the same package and they worked normally.
my $input = new Bio::TreeIO(-file => "bintree.nw",
-format => "newick");
my $tree = $input->next_tree;
my $tree_as_string = $tree->as_text($format);
print $tree_as_string;
The print Dumper($input) give this result:
$VAR1 = bless( {
'_bootstrap_style' => 'traditional',
'_handler' => bless( {
'_treelevel' => 0,
'_currentnodes' => [],
'_lastitem' => {
'tree' => 0,
'current' => [],
'id' => 0,
'node' => 0,
'leaf' => 0
},
'nodetype' => 'Bio::Tree::Node',
'_root_verbose' => 0,
'treetype' => 'Bio::Tree::Tree',
'_currentitems' => [],
'_nodect' => [
undef,
2,
0,
0,
0,
0,
0,
0,
0
]
}, 'Bio::TreeIO::TreeEventBuilder' ),
'_file' => 'bintree.nw',
'newline_each_node' => undef,
'internal_node_id' => 'id',
'_root_cleanup_methods' => [
sub { "DUMMY" }
],
'_flush_on_write' => 1,
'_filehandle' => \*Symbol::GEN0,
'_root_verbose' => 0,
'_print_tree_count' => 0
}, 'Bio::TreeIO::newick' );
Here is the Print Dumper ($tree)
is there a mistake ? or it's a bug ?
Thanks in advance
Your code is not working because you have not set the variable $format to anything, so the Bio::TreeIO class cannot find a class to load for the format. Try this code (it works for me):
#!/usr/bin/env perl
use strict;
use warnings;
use Bio::TreeIO;
my $usage = "$0 treefile\n";
my $infile = shift or die $usage;
my $treeio = Bio::TreeIO->new(-file => $infile, -format => 'newick');
print $treeio->next_tree->as_text('newick');
EDIT: Here is a version using your tree as the input:
#!/usr/bin/env perl
use strict;
use warnings;
use Bio::TreeIO;
my $treeio = Bio::TreeIO->new(-fh => \*DATA, -format => 'newick');
print $treeio->next_tree->as_text('newick');
__DATA__
(((A:5,B:5)90:2,C:4)25:3,D:10);
If we run this code, it prints the tree, as expected.
$ perl so18645089.pl
(((A:5,B:5)90:2,C:4)25:3,D:10);
I'm using BioPerl 1.6.901, the latest version (and the version the documentation on CPAN describes). Version 1.6.0 is very old (>5 years) and is not even on CPAN anymore. I bet if you upgrade, your troubles will disappear.

Populating an array of hashes with arrays of hashes

I am currently developing a piece of monitoring software that takes an input file of server names and ip addresses and creates a rudimentary database of information. I want to default some values as it processes the config file and it works fine for the first time round the loop but any subsequent entries get created with weird (well weird to me was the best way to describe it as it is probably correct and the code is wrong, as in the code is doing exactly what i have asked it to do but not necessarily what i want it to do).
the output from the code below looks like:
$VAR1 = [
{
'IPAddress' => '196.8.150.163',
'Boxname' => 'MPLRDFDSOAK1',
'CurrentStatusInfo' => {
'LineHandlersRunning' => [
{
'NumberOfGaps' => 0,
'LineHandlerName' => 'DEFAULT',
'NumberOfCommLinkDowns' => 0,
'LineHandlerUpTime' => 0,
'MemoryUsage' => 0
}
]
},
'PreviousStatusInfo' => {
'LineHandlersRunning' =>
$VAR1->[0]{'CurrentStatusInfo'}{'LineHandlersRunning'}[0]
]
}
},
{
'IPAddress' => '196.8.150.164',
'Boxname' => 'MPLRDFDSOAK2',
'CurrentStatusInfo' => {
'LineHandlersRunning' =>
$VAR1->[0]{'CurrentStatusInfo'}{'LineHandlersRunning'}
},
'PreviousStatusInfo' => {
'LineHandlersRunning' =>
$VAR1->[0]{'PreviousStatusInfo'}{'LineHandlersRunning'}
}
}
];
The following is the code:
#######################################################################################
# Version History #
#######################################################################################
# example of the ini file
#box=>MPLRDFDSOAK1;ip=>196.8.150.163
#box=>MPLRDFDSOAK2;ip=>196.8.150.164
use strict;
use warnings;
# include the library to allow easy access to command line arguments
use Getopt::Long;
# include the data dumper utility
use Data::Dumper;
my $usageInstructions = "Some instructions\n";
my $showMeTheInstructions = "";
my $iniFileToReadIn = "";
my #boxes;
# read in the command line arguments
GetOptions( "ini=s" => \$iniFileToReadIn,
"H|h|?!" => \$showMeTheInstructions);
if ($showMeTheInstructions)
{
print $usageInstructions;
exit 0;
}
readInINIFileIn($iniFileToReadIn, \#boxes) if ($iniFileToReadIn ne "");
print Dumper(\#boxes);
print "\n\#\n\# END OF DATA DUMP\n\#\n\n";
exit 0;
#######################################################################################
# subroutine to read in the ini file and create the empty records for the boxes
# specified
sub readInINIFileIn
{
my ($iniFile, $pointerToBoxes) = #_;
my $noCRLFOnString = "";
# open the file
open (ConfigFile, "<$iniFile") || die $!;
# read in all the lines into an array
my #configurationItems = <ConfigFile>;
# close the file
close (ConfigFile);
# temporary record storage
my %tempRecord;
# create the defaults for all boxes
my #LineHandlersRunning;
my %tmpLineHandlerRunning = ( LineHandlerName => "DEFAULT",
LineHandlerUpTime => 0,
NumberOfCommLinkDowns => 0,
NumberOfGaps => 0,
MemoryUsage => 0 );
push (#LineHandlersRunning, {%tmpLineHandlerRunning});
my %CurrentStatusInfo;
my %PreviousStatusInfo;
push #{ $CurrentStatusInfo{'LineHandlersRunning'} }, #LineHandlersRunning;
push #{ $PreviousStatusInfo{'LineHandlersRunning'} }, #LineHandlersRunning;
# loop through the config file and create the defaults for the database of boxes
foreach my $configLine (#configurationItems)
{
my #TokenisedLineFromFileItems = ();
my #TokenisedLineFromFileNameValuePairs = ();
# store parameters
# each line will be ; separated then => separated, as in each one will have a number of items separated by ;'s and
# each item will be be a name & value pair separated by =>'s
#TokenisedLineFromFileItems = split(/;/,$configLine);
# remove quote marks around the outside of each element of the newly created array
s/^"|"$//g foreach #TokenisedLineFromFileItems;
# create information in database record to add to boxes
foreach my $NameValuePair (#TokenisedLineFromFileItems)
{
#TokenisedLineFromFileNameValuePairs = split(/=>/,$NameValuePair);
$noCRLFOnString = $TokenisedLineFromFileNameValuePairs[1];
$noCRLFOnString =~ s/(\n|\r)//g;
$tempRecord{'Boxname'} = $noCRLFOnString if ($TokenisedLineFromFileNameValuePairs[0] eq "box");
$tempRecord{'IPAddress'} = $noCRLFOnString if ($TokenisedLineFromFileNameValuePairs[0] eq "ip");
}
# add all other defaults as blank
$tempRecord{'CurrentStatusInfo'} = {%CurrentStatusInfo};
$tempRecord{'PreviousStatusInfo'} = {%PreviousStatusInfo};
push(#$pointerToBoxes, {%tempRecord});
}
}
I don't have the patience to wade through all of your code, but I'll bet your problem is related to this aspect of the Data::Dumper output:
$VAR1->[0]{'CurrentStatusInfo'}{'LineHandlersRunning'}[0]
In other words, your data structure contains a reference to other parts of the structure.
Perhaps you think you are making a copy of part of the data structure, but instead you are getting a shallow copy rather than a deep copy? For example, I'm suspicious of this code:
$tempRecord{'CurrentStatusInfo'} = {%CurrentStatusInfo};
$tempRecord{'PreviousStatusInfo'} = {%PreviousStatusInfo};
If indeed the problem is related to shallow copying, the Clone module might help.
Use lexical filehandles, declare variables in the smallest possible scope. I do not know what your problem is, but it is most likely caused by some variable persisting longer than you think it does.
I'm guessing it's because these two lines end up pushing the same hash reference into two locations - so if you alter the hashref contents in one location, the other will change as well which is probably not what you want for default values.
As FM pointed out, this is why you have the circular reference in your Dumper output.
If someone I'm waiting to get off the phone takes long enough i'll refactor your code for you.
Update: ok, so without knowing the full scenario it's hard to say if this is a sensible approach. certainly you should look at the various INI parsing modules in CPAN, but here is a very quick tweak of your code, leaving your existing logic structure in place:
use strict;
use warnings;
use Getopt::Long;
use Data::Dumper;
my $cmd_help = "Some instructions\n";
my $show_help = "";
my $ini_file_path = "";
# read in the command line arguments
GetOptions( "ini=s" => \$ini_file_path,
"H|h|?!" => \$show_help );
if ($show_help) {
print $cmd_help;
exit 0;
}
if (! -f $ini_file_path) {
die "File '$ini_file_path' doesn't seem to exist.";
}
my $boxes = read_ini_file($ini_file_path);
print Dumper($boxes);
exit 0;
=head2 read_ini_file
read in the ini file and create the empty records for the boxes
=cut
sub read_ini_file {
my ($ini_file) = #_;
my #boxes;
my #config_lines;
{
# consider using File::Slurp
open (my $ini_fh, '<', $ini_file_path) || die $!;
#config_lines = <$ini_fh>;
chomp #config_lines; # remove \r\n
# file handle will close when $ini_fh goes out of scope
}
# create the defaults for all boxes
my %line_handlers_running_defaults = ( LineHandlerName => "DEFAULT",
LineHandlerUpTime => 0,
NumberOfCommLinkDowns => 0,
NumberOfGaps => 0,
MemoryUsage => 0 );
# loop through the config file and create the defaults for the database of boxes
foreach my $line (#config_lines) {
my %record;
my #token_pairs = map { s/^"//; s/^$//; $_ } split(/;/,$line);
# create information in database record to add to boxes
foreach my $pair (#token_pairs) {
my ($key, $val) = split(/=>/,$pair);
$record{Boxname} = $val if $key eq "box";
$record{IPAddress} = $val if $key eq "ip";
}
# add all other defaults as blank
$record{CurrentStatusInfo} = { LineHandlersRunning => [{%line_handlers_running_defaults}] };
$record{PreviousStatusInfo} = { LineHandlersRunning => [{%line_handlers_running_defaults}] };
push #boxes, \%record;
}
return \#boxes;
}
gives this output:
$VAR1 = [
{
'IPAddress' => '196.8.150.163',
'CurrentStatusInfo' => {
'LineHandlersRunning' => [
{
'NumberOfGaps' => 0,
'LineHandlerName' => 'DEFAULT',
'NumberOfCommLinkDowns' => 0,
'LineHandlerUpTime' => 0,
'MemoryUsage' => 0
}
]
},
'Boxname' => 'MPLRDFDSOAK1',
'PreviousStatusInfo' => {
'LineHandlersRunning' => [
{
'NumberOfGaps' => 0,
'LineHandlerName' => 'DEFAULT',
'NumberOfCommLinkDowns' => 0,
'LineHandlerUpTime' => 0,
'MemoryUsage' => 0
}
]
}
},
{
'IPAddress' => '196.8.150.164',
'CurrentStatusInfo' => {
'LineHandlersRunning' => [
{
'NumberOfGaps' => 0,
'LineHandlerName' => 'DEFAULT',
'NumberOfCommLinkDowns' => 0,
'LineHandlerUpTime' => 0,
'MemoryUsage' => 0
}
]
},
'Boxname' => 'MPLRDFDSOAK2',
'PreviousStatusInfo' => {
'LineHandlersRunning' => [
{
'NumberOfGaps' => 0,
'LineHandlerName' => 'DEFAULT',
'NumberOfCommLinkDowns' => 0,
'LineHandlerUpTime' => 0,
'MemoryUsage' => 0
}
]
}
}
];

RegSvr32 registering yet nothing actually registered

A rather odd experience. Using the latest PDK (v7.3) from ActiveState, I used perlctrl to build a COM DLL. Perlctrl ran without a hitch. OLEView read the typelib okay. RegSvr32 registered it okay. However ... there's no sign of it in registry, and anything that tries to use it fails. I hunted for the various UIDs using RegEdit and they're just not there.
The code is below. It's a wrapping of Lingua::ZH::WordSegmenter, but with the encoding changed to utf8 rather than gbk.
It's probably something obvious ...
package ZHWordSeg;
use strict;
use warnings;
use utf8;
use ws;
use Encode;
use constant STX => chr( 2 ); #[
use constant ETX => chr( 3 ); #]
use constant FS => chr( 28 ); #^
use constant RS => chr( 30 ); #~
use constant TAB_SEPARATOR => 0;
use constant CARET_SEPARATOR => 1;
use constant FS_SEPARATOR => 2;
use constant SPACE_SEPARATOR => 3;
use constant AS_ARRAY => 4;
use feature 'switch';
our $segmenter;
sub ZHWordSeg_Setup {
my $dic = shift;
my $dic_encoding = shift;
my $separator = shift;
my $verbose = shift;
$dic_encoding = 'utf8' unless defined( $dic_encoding );
$separator = " " unless defined( $separator );
$verbose = 0 unless defined( $verbose );
if ( defined( $dic ) ) {
$segmenter = ws->new( dic => $dic, dic_encoding => $dic_encoding, seperator => $separator, verbose => $verbose );
} else {
$segmenter = ws->new( dic_encoding => $dic_encoding, seperator => $separator, verbose => $verbose );
}
}
sub ZHWordSeg {
my $source = shift;
print STDERR $source;
my $sepcode = shift;
$source = encode("utf8",$source);
my $stringres = $segmenter->seg($source);
my #arrayres;
given ($sepcode) {
when (TAB_SEPARATOR) {
$stringres =~ tr/ /\t/;
return $stringres;
}
when (CARET_SEPARATOR) {
$stringres =~ tr/ /^/;
$stringres .= "^";
return $stringres;
}
when (FS_SEPARATOR) {
$stringres =~ s/ /FS/eg;
$stringres .= FS;
return $stringres;
}
when (SPACE_SEPARATOR) {
return $stringres;
}
default {
#arrayres = split( / /, $stringres );
return \#arrayres;
}
}
}
sub SetDictionary {
my ($source) = shift;
my $res = set_dic($source);
return $res;
}
1;
=pod
=begin PerlCtrl
%TypeLib = (
PackageName => 'ZHWordSeg',
DocString => 'Chinese word segmentation',
HelpContext => 1,
TypeLibGUID => '{F6C9BD66-7CA1-4610-B77F-E219A7122C18}', # do NOT edit this line
ControlGUID => '{45D47C6A-2B9A-4D62-9CFD-F18C95DC00C5}', # do NOT edit this line either
DispInterfaceIID=> '{007E4E7A-3B75-4DC3-864C-7746860941B3}', # or this one
ControlName => 'BOCWS',
ControlVer => 2, # increment if new object with same ProgID
# create new GUIDs as well
ProgID => 'ZHWordSeg.BOCWS',
LCID => 0,
DefaultMethod => 'ChineseWordSegmenter',
Methods => {
'ChineseWordSegmenter' => {
RetType => VT_VARIANT,
TotalParams => 2,
NumOptionalParams => 1,
ParamList =>
[ 'source' => VT_BSTR,
'sepcode' => VT_I4
]
},
'ChineseWordSegmenter_Setup' => {
RetType => VT_VARIANT,
TotalParams => 4,
NumOptionalParams => 4,
ParamList =>
[ 'dic' => VT_BSTR,
'dic_encoding' => VT_BSTR,
'separator' => VT_BSTR,
'verbose' => VT_BSTR
]
}
}, # end of 'Methods'
Properties => {
TAB_SEPARATOR => {
DocString => "Separate items with TAB (0x0)",
Type => VT_I4,
DispID => 3,
ReadOnly => 1,
},
CARET_SEPARATOR => {
DocString => "Separate items with ^ (0x1)",
Type => VT_I4,
DispID => 4,
ReadOnly => 1,
},
FS_SEPARATOR => {
DocString => "Separate items with ascii 28 (0x2)",
Type => VT_I4,
DispID => 5,
ReadOnly => 1,
},
SPACE_SEPARATOR => {
DocString => "Separate items with space (0x3)",
Type => VT_I4,
DispID => 6,
ReadOnly => 1,
},
AS_ARRAY => {
DocString => "Separate items as array (0x4)",
Type => VT_I4,
DispID => 7,
ReadOnly => 1,
}
}, # end of 'Properties'
); # end of %TypeLib
=end PerlCtrl
=cut
This is the .perlctrl file, in case it matters:
#!C:\Program Files\ActiveState Perl Dev Kit 7.3 Deployment\bin\lib\pai.exe
PAP-Version: 1.0
Packer: C:\Program Files\ActiveState Perl Dev Kit 7.3 Deployment\bin\perlctrl.exe
Script: ZHWordSeg.ctrl
Cwd: P:\BOCWS
Byref: 0
Clean: 0
Date: 2008-10-24 18:05:42
Debug: 127.0.0.1:2000
Dependent: 0
Dyndll: 0
Exe: BOCWS.dll
Force: 1
Gui: 0
Hostname: xi
No-Compress: 0
No-Gui: 0
No-Logo: 0
Runlib:
Shared: none
Singleton: 0
Tmpdir:
Verbose: 0
Version-Comments:
Version-CompanyName:
Version-FileDescription: Wrapper of Lingua::ZH::WordSegmenter.pm
Version-FileVersion: 1.0
Version-InternalName: ZHWordSeg
Version-LegalCopyright:
Version-LegalTrademarks:
Version-OriginalFilename: ZHWordSeg.ctrl
Version-ProductName: BOChineseWordSegmenter
Version-ProductVersion: 1.0
Warnings: 0
Xclude: 1
The only "solution" that I've found was suggested over on news:comp.os.ms-windows.programmer.win32
i am not a PDK user but from experience i can tell you, that you should check the DllRegister exports code and what it internally does, since this is what the regsvr32 calls and this code is creating the registry keys for your com server/proxy, etc, ...
You can track the registry for changes with sysinternal tools like regmon or procmon, just to make sure!
Ultimately, I gave up and went back to a previous version that worked and tweaked it.