Altair: How to make scatter plot aligned with image background created by mark_image? - visualization

I'm looking for a working example to have a .png picture as the background of a scatter chart.
Currently, I use mark_image to draw the background image:
source = pd.DataFrame.from_records([
{"x": 0, "y": 0,
"img": "http://localhost:8888/files/BARTStreamlit/assets/BARTtracksmap.png?_xsrf=2%7Ce13c35be%7Ce013c83479b892363239e5b6a77d97dc%7C1652400559"}
])
tracksmap = alt.Chart(source).mark_image(
width=500,
height=500
).encode(
x='x',
y='y',
url='img'
)
tracksmap
Here is the resulted image drown:
and draw the scater chart,
chart = alt.Chart(maptable).mark_circle(size=60).encode(
x= 'x',
y= 'y',
tooltip=['short_name', 'ENTRY']
).interactive()
chart
I have scaled the x, y channel values for the scatter chart to be in the range of [0, 500]. 500 is the width and height of the background image that I guessed.
Here is the resulted scatter plot:
then I combined the two chart with layer mechanism:
geovizvega = alt.layer(tracksmap, chart)
geovizvega
resulting the following:
The two charts do not align. I'd like to have the scatter dots aligning with the tracks on the background image. How can I achieve that?
To have them aligned, I might need to have the background image's top left corner at the coordinates (0, 0), how can I achieve that? (It seems that the x, y channel values for mark_image is the coordinates of the center of the image? With accurate definition of the x, y channel values, it might be possible to calculate the proper value of x, and y for the top left coroner to be at (0, 0)).
I might need to to have precise dimension of the background image. How?
My above approach may not be the right one. Please show me a working example.

Yes, if you change the values of x and y in your image plot to something like y=-200 and x=200, the image should be more centered in the scatter plot.
You can also change the anchor point of the image using align and baseline:
import altair as alt
import pandas as pd
source = pd.DataFrame.from_records([
{"x": 2, "y": 2, "img": "https://vega.github.io/vega-datasets/data/7zip.png"}
])
imgs = alt.Chart(source).mark_image(
width=100,
height=100
).encode(
x='x',
y='y',
url='img'
)
imgs + imgs.mark_circle(size=200, color='red', opacity=1)
imgs = alt.Chart(source).mark_image(
width=100,
height=100,
align='right',
baseline='top'
).encode(
x='x',
y='y',
url='img'
)
imgs + imgs.mark_circle(size=200, color='red', opacity=1)
After this, you would still need to change the dimensions of the chart so that it has the same size as the image. The default is width=400 and height=300. You can get the dimensions of your image in most image editing software or using the file <imagename> command (at least on linux). But even after getting these dimensions, you would have to do some manual adjustments due to axes taking up some of that space in the chart.

Related

Halcon - get area of region in world coordinates

I have following code:
image_points_to_world_plane (CamParam, Pose, intersection_points_row, intersection_points_col, 'mm', X1, Y1)
distance_pp (X1[2], Y1[2], X1[3], Y1[3], Measure1)
this code retunrs the values in mm.
now the code goes on as shown below, and I would need the area of the Regions1 in mm². Instead i get them in pixel..
access_channel(Image, ImageMono, 1)
threshold(ImageMono, Region, 0, 100)
fill_up(Region, RegionFillUp)
reduce_domain(ImageMono, RegionFillUp, ImageReduced)
threshold (ImageReduced, Regions1, 230, 255)
connection (Regions1, Connection)
select_shape(Connection, Labels, 'area', 'and', 2000, 99999)
area_center(Labels, AreaLabels, RowLabels, ColumnLabels)
AreaLabels is in px² and i would need it in mm². but couldnt find anything like region_to_world_plane... how can this be done?
Try looking at the operator "image_to_world_plane". It will transform the image so that the pixel size is in metric units (or whatever you prefer). It will also warp the image so that it looks as if the picture was taken directly from overhead. Then any area calculations you perform on this transformed image will be in the units you specified (mm, m, etc).

Getting the coordinates of vertices of an A4 sheet with coins on it, for its further projective transformation and coin detection

I need to transform my tilted image in a way I can find coins on an A4 paper. So far, I have been getting four coordinates of edges of my paper by manually selecting them with ginput.
targetImageData = imread('coin1.jpg');
imshow(targetImageData);
fprintf('Corner selection must be clockwise or anti-clockwise.\n');
[X,Y] = ginput(4);
Is there a way to automate this process, say, apply some edge detector and then find coordinates of each vertex and then pass them as the coordinates needed for transformation?
Manual selection:
Result:
You can try using detectHarrisFeatures on the S color channel of HSV color space:
I was looking for a color space that gets maximum contrast of the paper.
It looks like the saturation color channel of HSV makes a good contrast between the paper and the background.
Image is resized the image by a factor of 0.25, for removing noise.
detectHarrisFeatures finds the 4 corners of the paper, but it might not be robust enough.
You may need to find more features, and find the 4 correct features, using some logic.
Here is a code sample:
%Read input image
I = imread('im.png');
%Remove the margins, and replace them using padding (just because the image is a MATLAB figure)
I = padarray(I(11:end-10, 18:end-17, :), [10, 17], 'both', 'replicate');
HSV = rgb2hsv(I);
%H = HSV(:, :, 1);%figure;imshow(H);title('H');
S = HSV(:, :, 2);%figure;imshow(S);title('S');
%V = HSV(:, :, 3);%figure;imshow(V);title('V');
%Reduce image size by a factor of 0.25 in each axis
S = imresize(S, 0.25);
%S = imclose(S, ones(3)); %May be requiered
%Detect corners
corners = detectHarrisFeatures(S);
imshow(S); hold on;
plot(corners.selectStrongest(4));
Result:
Different approach you may try:
Take a photo without the coins.
Mark the corners manually, and extract features of the 4 corners.
Use image matching techniques to match the image with the coins with the image without the coins (mach basted on the 4 corners).

How to format a minimalist chart with jFreeChart?

I generate a transparent chart that lets the background of a web page be seen through it.
So far I've done this (omited the populating of dataset for brevity):
lineChartObject=ChartFactory.createLineChart("Title","Legend","Amount",line_chart_dataset,PlotOrientation.VERTICAL,true,true,false);
CategoryPlot p = lineChartObject.getCategoryPlot();
Color trans = new Color(0xFF, 0xFF, 0xFF, 0);
lineChartObject.setBackgroundPaint(trans);
p.setBackgroundPaint(trans);
for (int i=0;i<=3;i++){
lineChartObject.getCategoryPlot().getRenderer().setSeriesStroke(i, new BasicStroke(3.0f));
lineChartObject.getCategoryPlot().getRenderer().setBaseItemLabelsVisible(false);
}
Which renders this:
I cannot find a way of:
Removing border of plot (1)
Removing border of leyend as well as making it transparent (3)
Making the labels on the X axis (2) to behave intelligently as the labels of Y axis do (A). Labels of Y axis space themselves so as to not clutter the graph, for example if I rendered the graph smaller, it would show fewer labels, like this:
Edit: X label domain is dates.
For (1) try:
plot.setOutlineVisible(false);
For (2), a common reason for having too many categories along the x-axis is that the data is actually numerical, in which case you should be using XYPlot rather than CategoryPlot. With XYPlot, the x-axis scale adjusts in the same way that the y-axis does.
Edit from OP: Using a TimeSeriesChart with a TimeSeriesCollection as XYDataSet did the work! (fotgot to say X domain is dates)
For (3) try:
LegendTitle legend = chart.getLegend();
legend.setFrame(BlockBorder.NONE);
legend.setBackgroundPaint(new Color(0, 0, 0, 0));

Matlab overlaying color on an image

I have a grascale image where I want to overlay different colors to different areas that have similar properties (say direction or intensity etc.) I am not referring to a heat map. Rather I have hard coded segmentation code where I have grouped pixels together by their "similarities". Now I want to over lay colors to those pixels.
For example, for a 3x3 pixel pic, say I know that the top row and bottom row are similar group. And the middle row is another group. How can I overlay a red hue with one group and a blue hue with another?
You could make your 3x3x1 grayscale image into a 3x3x3 color image, and then adjust the hue values for the pixels you want.
So say:
GreyImg=[0.2, 0.3, 0.35;...
0.5, 0.6, 0.56;...
0.8, 0.8, 0.85];
%Convert To Color Img
ColorImg(:,:,1)=GreyImg;
ColorImg(:,:,2)=GreyImg;
ColorImg(:,:,3)=GreyImg;
%Add a red hew to top row:
ColorImg(1:1,:,1)=ColorImg(1:1,:,1)+[.2, .2, .2];
%Add a blew hew to top row:
ColorImg(3:3,:,3)=ColorImg(3:3,:,3)+[.2, .2, .2];
imshow(ColorImg);

Amplitude of graph clips when magnified

This is the code for plotting I am using
figure
x = -pi:pi/40:pi;
plot(x,cos(5*x),'-ro',x,sin(5*x),'-.b')
hleg1 = legend('cos_x','sin_x');
The output comes like this:
When I try to stretch the time axis, what I get is like this:
But as can be seen, the amplitude gets clipped when I stretch the time axis. How do I avoid this clipping of amplitude when stretching time axis and v.V?
You can try using "Zoom In," the plus-magnifying glass icon and being very careful to select the entire vertical range of the image. To control the minimum and maximum values of the axes more precisely using the axis function.
figure
x = -pi:pi/40:pi;
plot(x,cos(5*x),'-ro',x,sin(5*x),'-.b')
hleg1 = legend('cos_x','sin_x');
axis([1.6, 3.2,-1, 1])