Combined SVG does not move by pixel while translating - ruby

I am using Ruby to combine a list of existed SVG (trigger with XHR by react-inlinesvg - if someone wants to know) to display it on my views. The existed SVG size are all 90x90 . By using rmagick I can get its bounding box size, then translate the next element with these size. A simplified code will be like this:
# Preparing svg, <svg> tag, xml, etc..
...
divider = ''
shift = 0
svg_path.map do |svg|
canvas = ImageList.new(svg) # from rmagick
canvas.trim!
width = canvas.columns # get the bounding box after trimming
content = svg_content(svg) # Read content of existed svg
output = "<g transform='translate(#{shift}, 0)'>" + content +"</g>" + divider
shift += width + 10 # A small space between each svg
# Add divider
divider = "<g transform='translate(#{shift}, 0)'>" + #divider + "</g>"
end
...
# Add </svg> tag
Expected
Result
The link above is a demonstration for my problem, the real SVG is much more complicated.
The problem here is: I can get the exactly size of each element by pixel, however when I translating the next element with those sizes, it does not move as I expected.

Related

Making a long image without resizing

I need to put many images together side by side but without changing the height or width of any of them. That is to say, it will just be one image of a constant height but very long width as the image are sitting horizontally.
I've been using Python and the PIL library but what I've tried so far is producing an image that makes all the images smaller to concatenate into one long image.
Image.MAX_IMAGE_PIXELS = 100000000 # For PIL Image error when handling very large images
imgs = [ Image.open(i) for i in list_of_images ]
widths, heights = zip(*(i.size for i in imgs))
total_width = sum(widths)
max_height = max(heights)
new_im = Image.new('RGB', (total_width, max_height))
# Place first image
new_im.paste(imgs[0],(0,0))
# Iteratively append images in list horizontally
hoffset=0
for i in range(1,len(imgs),1):
hoffset=imgs[i-1].size[0]+hoffset # update offset**
new_im.paste(imgs[i],(hoffset,0))
new_im.save('row.jpg')
The result I'm getting now is one image made up of concatenated images in a horizontal row. This is what I want, except the images are being made smaller and smaller in the concatenation process. I want the end result to not make the images smaller and instead produce an image made of the input images with their original size. So the output image will just have to have a very long width.
It seems you have a bug while updating the offsets.
You should replace your iteration block with:
imgs = [Image.open(i) for i in list_of_images]
widths, heights = zip(*(i.size for i in imgs))
new_img = Image.new('RGB', (sum(widths), max(heights)))
h_offset = 0
for i, img in enumerate(imgs):
new_img.paste(img, (h_offset, 0))
h_offset += img.size[0]

PIL: Imageobject.save() after drawing completely corrupts images and smurfs the ouput

I have these two functions in my program:
def depict_ph_increase(x,y,color, imobject):
program_print(color)
draw = PIL.ImageDraw.Draw(imobject)
draw.text((x, y),color,(255,255,255))
imobject.save('tmp-out.gif')
im_temp = PIL.Image.open("tmp-out.gif")#.convert2byte()
im_temp = im_temp.resize((930, 340), PIL.Image.ANTIALIAS)
MAP_temp = ImageTk.PhotoImage(im_temp)
map_display_temp = Label(main, image=MAP_temp)
map_display_temp.image = MAP_temp # keep a reference!
map_display_temp.grid(row=4,column=2, columnspan=3)
def read_temp_pixels(temperature_file, rngup, rngdown):
temp_image_object = PIL.Image.open(temperature_file)
(length, width) = get_image_size(temp_image_object)
(rngxleft, rngxright) = rngup
(rngyup,rngydown) = rngdown
print 'the length and width is'
print length, width
hotspots = 5;
for hotspot in range(0,hotspots):
color = "#ffffff"
while color == "#ffffff" or color == "#000000" or color == "#505050" or color == "#969696":
yc = random.randint(rngxleft, rngxright)
xc = random.randint(rngyup,rngydown)
color = convert_RGB_HEX(get_pixel_color(temp_image_object, xc, yc))
depict_ph_increase(xc,yc,color, temp_image_object)
The bottom one calls the top one. Their job is to read in this image:
It then randomly selects a few pixels, grabs their colors, and writes the hex values of the colors on top. But, when it redisplays the image, it gives me this garbage:
Those white numbers up near the upper right corner are the hex values its drawing. Its somehow reading the values from the corrupted image, despite the fact that I don't collect the values until AFTER I actually call the ImageDraw() method. Can someone explain to me why it is corrupting the image?
Some background--the get_pixel_color() function is used several other times in the program and is highly accurate, its just reading the pixel data from the newly corrupted image somehow. Furthermore, I do similar image reading (but not writing) at other points in my code.
If there is anything I can clarify, or any other part of my code you want to see, please let me know. You can also view the program in its entirety at my github here: https://github.com/jrfarah/coral/blob/master/src/realtime.py It should be commit #29.
Other SO questions I have examined, to no avail: Corrupted image is being saved with PIL
Any help would be greatly appreciated!
I fixed the problem by editing this line:
temp_image_object = PIL.Image.open(temperature_file)
to be
temp_image_object = PIL.Image.open(temperature_file).convert('RGB')

D3 expanding rectangle's text is not adjusted

I have a rectangle and a text created through D3 which are grouped together like below.
<g>
<rect></rect>
<text></text>
</g>
In a javascript function I'm expanding this rectangle's width to allow the the value of text to be displayed in one go. (If the value is too long as the text value is set dynamically). This is working fine. However even though the rectangle width is expanding depending on the text value size , D3 text element is not showing the complete text value that is added, eventually the text is moved to left and the first bit of it can't be seen.
Do I need to increase the text element's width too or what would be the solution for this?
[UPDATE]
Following is the current code.
var elms = d3.selectAll("[id=s]"); // has the rectangle and text elements
var s = d3.selectAll("[id=s]").selectAll("text"); // just the text elements
var minimumValue = 100;
// updating rectangle width
elms.attr('width', function() { return dynamic < minimumValue ? minimumValue : dynamic;});
Now I need a way to update the position of the text element when the rectangle is expanded. Hope this is more clear. I just tried manually updating 'x' property of text element that works. But can I derive this value dynamically to set it within this function?
In case someone is looking for this, was able to get the text new 'x' value by x of rectangle + half of rectangle's width (and similar for y but with the height).
Got the answer from this link (How to place and center text in an SVG rectangle)

Print image to pdf without margin using Matlab

I'm trying to use the answers I found in these questions:
How to save a plot into a PDF file without a large margin around
Get rid of the white space around matlab figure's pdf output
External source
to print a matlab plot to pdf without having the white margins included.
However using this code:
function saveTightFigure( h, outfilename, orientation )
% SAVETIGHTFIGURE(H,OUTFILENAME) Saves figure H in file OUTFILENAME without
% the white space around it.
%
% by ``a grad student"
% http://tipstrickshowtos.blogspot.com/2010/08/how-to-get-rid-of-white-margin-in.html
% get the current axes
ax = get(h, 'CurrentAxes');
% make it tight
ti = get(ax,'TightInset');
set(ax,'Position',[ti(1) ti(2) 1-ti(3)-ti(1) 1-ti(4)-ti(2)]);
% adjust the papersize
set(ax,'units','centimeters');
pos = get(ax,'Position');
ti = get(ax,'TightInset');
set(h, 'PaperUnits','centimeters');
set(h, 'PaperSize', [pos(3)+ti(1)+ti(3) pos(4)+ti(2)+ti(4)]);
set(h, 'PaperPositionMode', 'manual');
set(h, 'PaperPosition',[0 0 pos(3)+ti(1)+ti(3) pos(4)+ti(2)+ti(4)]);
% save it
%saveas(h,outfilename);
if( orientation == 1)
orient portrait
else
orient landscape
end
print( '-dpdf', outfilename );
end
Results in this output:
As you can see the 'PaperSize' seems to be set not properly. Any idea of possible fixes?
NOTE
If I change the orientation between landscape and portrait the result is the same, simply the image is chopped in a different way.
However if I save the image with the saveas(h,outfilename); instruction the correct output is produced.
Why is this? And what is the difference between the two saving instructions?
Alltogether the answers you mentioned offer a lot of approaches, but most of them didn't worked for me neither. Most of them screw up your papersize when you want to get the tight inset, the only which worked for me was:
set(axes_handle,'LooseInset',get(axes_handle,'TightInset'));
I finally wrote a function, where I specify the exact height and width of the output figure on paper, and the margin I want (or just set it to zero). Be aware that you also need to pass the axis handle. Maybe this functions works for you also.
function saveFigure( fig_handle, axes_handle, name , height , width , margin)
set(axes_handle,'LooseInset',get(axes_handle,'TightInset'));
set(fig_handle, 'Units','centimeters','PaperUnits','centimeters')
% the last two parameters of 'Position' define the figure size
set(fig_handle,'Position',[-margin -margin width height],...
'PaperPosition',[0 0 width+margin height+margin],...
'PaperSize',[width+margin height+margin],...
'PaperPositionMode','auto',...
'InvertHardcopy', 'on',...
'Renderer','painters'... %recommended if there are no alphamaps
);
saveas(fig_handle,name,'pdf')
end
Edit: if you use painters as renderer saveas and print should produce similar results. For jpegs print is preferable as you can specify the resolution.

d3 autospace overlapping tick labels

Is there a way in d3 to not draw overlapping tick labels? For example, if I have a bar chart, but the bars are only 5 pixels wide and the labels are 10 pixels wide, I end up with a cluttered mess. I'm currently working on an implementation to only draw the labels when they do not overlap. I can't find any existing way to do that, but wasn't sure if anyone else had dealt with this problem.
There is no way of doing this automatically in D3. You can set the number of ticks or the tick values explicitly (see the documentation), but you'll have to figure out the respective numbers/values yourself. Another option would be to rotate the labels such that there is less chance of them overlapping.
Alternatively, like suggested in the other answer, you could try using a force layout to place the labels. To clarify, you would use the force layout on the labels only -- this is completely independent of the type of chart. I have done this in this example, which is slightly more relevant than the one linked in the other answer.
Note that if you go with the force layout solution, you don't have to animate the position of the labels. You could simply compute the force layout until it converges and then plot the labels.
I've had a similar problem with multiple (sub-)axis, where the last tick overlaps my vertical axis in some situations (depending on the screen width), so I've just wrote a little function that compares the position of the end of the text label with the position of the next axis. This code is very specific to my use case, but could adapted easily to your needs:
var $svg = $('#svg');
// get the last tick of each of my sub-axis
$('.tick-axis').find('.tick:last-of-type').each(function() {
// get position of the end of this text field
var endOfTextField = $(this).offset().left + $(this).find('text').width();
// get the next vertical axis
var $nextAxis = $('line[data-axis="' + $(this).closest('.tick-axis').attr('data-axis') + '"]');
// there is no axis on the very right, so just use the svg width
var positionOfAxis = ($nextAxis.length > 0) ? $nextAxis.offset().left : $svg.offset().left + $svg.width();
// hide the ugly ones!
if (endOfTextField > positionOfAxis) {
$(this).attr('class', 'tick hide');
}
});
The ticks with color: aqua are the hidden ones:

Resources