Cannot set property as opacity for extrusion layer in mapbox - reactjs

The bounty expires in 2 days. Answers to this question are eligible for a +200 reputation bounty.
slevin wants to draw more attention to this question.
I use mapbox 2.10 and react 18.2. I have a mapbox fill-extrusion that gets a filter after a button click
map.current.setFilter('my-extrude', ['==',["id"] , 0] )
to show some extruded polygons.
In that layer I try to set a value for each polygon based on a property of the feature.
This doesnt work, I get Error: The layer 'my-extrude' does not exist in the map's style and cannot be filtered. probably because of the error in setting the opacity. If I set the opacity to a static number like 0.6, all works well.
What am I missing?
Thanks
map.current.addLayer({'id': 'my-extrude',
'type': 'fill-extrusion',
'source': 'my-extrude',
'paint': {
'fill-extrusion-color':[
'case',
['boolean', ['feature-state', 'hover'], false],'rgb(253, 255, 0)',
['boolean', ['feature-state', 'click'], false],'rgb(253, 255, 0)',
'rgb(253, 255, 72)'
] ,
'fill-extrusion-opacity':['get', 'customTop'],
'fill-extrusion-height': ['+',['to-number', ['get', 'customTop']] , ['to-number', ['get', 'customHeight']]],
'fill-extrusion-base': ['+',['to-number', ['get', 'customTop']], ['to-number', ['get', 'customBase']]]
}
});

it seems to me that instead of using 'feature-state' you should create a variable which will get the state of the map element on the page, and if the state is hover then give a static number for that case, and if the state is clicked then give a different static number.

Here most probably because you forgot to convert customTop to number just like you did for fill-extrusion-height and fill-extrusion-base and the error occures because fill-extrusion-opacity only accepts numbers between 0 and 1.
'fill-extrusion-opacity' : ['to-number', ['get', 'customTop']]
Note also when you use a variable to define fill-extrusion-opacity it is recommanded to set it with an interpolate expressions to make fill-extrusion-opacity always between 0 and 1.
Interpolate :
Produces continuous, smooth results by interpolating between pairs of input and output values ("stops"). The input may be any numeric expression (e.g., ["get", "population"]). Stop inputs must be numeric literals in strictly ascending order. The output type must be number, array, or color.
There are multiple ways to interpolate and the one needed here is the "linear" type :
Interpolates linearly between the pair of stops just less than and just greater than the input.
Inspired by this example from docs that uses the interpolate operator to define a linear relationship between zoom level and circle size using a set of input-output pairs
{
"circle-radius": [
"interpolate", ["linear"], ["zoom"],
// zoom is 5 (or less) -> circle radius will be 1px
5, 1,
// zoom is 10 (or greater) -> circle radius will be 5px
10, 5
]
}
with the same logic :
{
"fill-extrusion-opacity": [
"interpolate", ["linear"], ['to-number', ['get', 'customTop']],
// customTop is 0 (or less) -> fill-extrusion-opacity will be 0
0, 0,
// customTop is 1 (or greater) -> fill-extrusion-opacity will be 1
1, 1
]
}

Related

Swift Design: why array.endIndex is large than real lastest index and CGRect.maxY is same

In the process of programming in swift, I encountered such a problem which confused me.
as shown in the picture above。
I found that the maxY property of CGRect is actually not included in CGRect. Because for a CGRect whose origin coordinate is (0, 0) and the length and width are 100, its actual maxY should be (0, 99).
I also found that the same problem exists in Array, for example, an array of [0, 1, 2, 3, 4, 5], his subscript should be 0-5, but the endIndex property of Array is 6.
I wonder why it is designed this way, does it make any sense?
Senario 1
CGRect.contains(_:) return true only if the coordinate is inside the rectangle or it is on the minimumX & minimumY edges.
If the point lies on the maximum edges it will return false.
In your case you are trying to check a point which lies on the maximum edge of the rect. So it will return ```false``.
Check the Documentation
A point is considered inside the rectangle if its coordinates lie inside the rectangle or on the minimum X or minimum Y edge.
Senario 2
endIndex of an array is defined as follows.
The array’s “past the end” position—that is, the position one greater than the last valid subscript argument.
So in your array,
5 is the last valid element which has the index of 5. So endIndex is defined as the 1 value higher than the index of the last element. So it will return 6.
CGRect.contains is actually refers CGRectContainsPoint . As the documentation says
A point is considered inside the rectangle if its coordinates lie inside the rectangle or on the minimum X or minimum Y edge.
So why?. Lets think we have a frame like CGRect(x: 0, y: 0, width: 3, height: 3)
What we expect that , We want a frame that x position is 0 and width must be 3.
From 0 to 3 Its like :
0->1->2->3
Numbers are point , arrows like feet
The distance is 3 yes but there is 4 points thats why Apple wants to eliminate 1 point. We can say that this is the last point from documentation. Thats why print(rect.contains(.init(x: 0, y: 0))) is true and print(rect.contains(.init(x: rect.maxX, y: rect.maxY))) or any other end point is not true

ValueError: could not broadcast input array from shape (180,180,3) into shape (1,3,180,180)

I'm trying to get an image shape of (1,3,180,180) from original shape, which is (1224, 1842, 3). I've tried specifying the shape like this:
im_cv = cv.imread('test.jpg')
im_cv = cv.resize(im_cv, (1,3,180,180))
But get the error
File "/Users/lucasjacaruso/Desktop/hawknet-openvino/experiment.py", line 47, in <module>
im_cv = cv.resize(im_cv, (1,3,180,180))
cv2.error: OpenCV(4.5.3-openvino) :-1: error: (-5:Bad argument) in function 'resize'
> Overload resolution failed:
> - Can't parse 'dsize'. Expected sequence length 2, got 4
> - Can't parse 'dsize'. Expected sequence length 2, got 4
However, the model will not accept anything other than (1,3,180,180). If I simply specify the shape as (180,180), it's not accepted by the model:
ValueError: could not broadcast input array from shape (180,180,3) into shape (1,3,180,180)
How can I get the shape to be (1,3,180,180)?
Many thanks.
resize is to change the image dimensions, e.g. to change the image from (180,180,3) to say (300,300,3).
You need to add a new dimension with np.newaxis. Further, as imread will return the depth (color) dimension as axis 2, you need to move the axis:
im_cv = np.moveaxis(im_cv, 2, 0)[np.newaxis]

How to show an inverted line in reactjs charts 2?

Is there a way to show inverted line graphs in reactjs-charts-2 ?
For example, we are tracking number of complaints per month.
The more complaints there are, the lower we want the graph to go, with 0 complaints being at the top of the graph.
So the Y scaling should be reversed:
0
1
2
3
4
5
and so on...
The only way I know to do it currently is to multiply all values by -1. But then the Y axis values show the negative number. Not pretty.
I found the answer. You need to add this to the options object:
scales: {
yAxes: [{
ticks: {
reverse: true
}
}]
}

Plotting arrays using a grouped horizontal bar graph

I am trying to generate a graph that should look similar to:
My arrays are:
Array4:[Nan;Nan;.......;20;21;22;23;24;..........60]
Array3:[[Nan;Nan;.......;20;21;22;23;24;..........60]
Array2:[0;1;2;3;4;5;6;Nan;Nan;Nan;Nan;17;18;.....60]
Array1:[0;1;2;3;4;5;6;Nan;Nan;Nan;Nan;17;18;.....60]
I cannot find the right way to group my arrays in order to plot them in the way shown on the above graph.
I tried using the following function explained in: http://uk.mathworks.com/help/matlab/ref/barh.html
barh(1:numel(x),y,'hist')
where y=[Array1,Array2;Array3,Array4] and x={'1m';'2m';'3m';......'60m'}
but it does not work.
Why Your Current Approach Isn't Working
Your intuition makes sense to me, but the barh function you are using doesn't work the way you think it does. Specifically, you are interpreting the meaning of the x and y inputs to that function incorrectly. Those are inputs are constant values, not entire axes. The first y input refers to the end-point of the bar that stretches horizontally from x = 0 and the first x input refers to location on the y-axis of the horizontal bar. To illustrate what I mean, I've provided the below horizontal bar graph:
You can find this same picture in the official documentation of the MATLAB barh function. The code used to generate this bar graph is also given in the documentation, shown below:
x = 1900:10:2000;
y = [57,91,105,123,131,150,...
170,203,226.5,249,281.4];
figure;
barh(x, y);
The individual elements of the x array, rather confusingly, show up on the y-axis as the starting locations of each bar. The corresponding elements of the y array are the lengths of each bar. This is the reason that the arrays must be the same length, and this illustrates that they are not specifications of the x and y axes as one might intuitively believe.
An Approach To Solve Your Problem
First things first, the easiest approach is to do this manually with the plot function and a set of lines that represent floating bars. Consult the official documentation for the plot function if you'd like to plot the lines with some sort of color coordination in mind - the code I present (modified version of this answer on StackOverflow) just switches the color of the floating bars between red and blue. I tried to comment the code so that the purpose of each variable is clear. The code I present below matches the floating bar graph that you want to be plotted, if you are alright with replacing thick floating bars with 2D lines floating on a plot.
I used the data that you gave in your question to specify the floating horizontal bars that this script would output - a screenshot is shown below the code. Array1 & Array2:[0;1;2;3;4;5;6;Nan;Nan;Nan;Nan;17;18;.....60], these arrays go from 0 to 6 (length = 6) and 17 to 60 (length = 60 - 17 = 43). Because there is a "discontinuity" of sorts from 7 to 16, I have to define two floating bars for each array. Hence, the first four values in my length array are [6, 6, 43, 43]. Where the first 6 and the first 43 correspond to Array1 and the second 6 and the second 43 correspond to Array2. Recognizing this "discontinuity", the starting point of the first floating bar for Array1 and Array2 is x = 0 and the starting point of the second floating bar for Array1 and Array2 is x = 7. Putting that all together, you arrive at the x-coordinates for the first four points in the floating_bars array, [0 0; 0 1.5; 17 0; 17 1.5]. The y-coordinates in this array only serve to distinguish Array1, Array2, and so on from each other.
Code:
floating_bars=[0 0; 0 1.5; 17 0; 17 1.5; 20 6; 20 7.5]; % Each row is the [x,y] coordinate pair of the starting point for the floating bar
L=[6, 6, 43, 43, 40, 40]; % Length of each consecutive bar
thickness = 0.75;
figure;
for i=1:size(floating_bars,1)
curr_thickness = 0;
% It is aesthetically pleasing to have thicker bars, this makes the plot look for like the grouped horizontal bar graph that you want
while (curr_thickness < thickness)
% Each bar group has two bars; set the first to be red, the second to be blue (i.e., even index means red bar, odd index means blue bar)
if mod(i, 2)
plot([floating_bars(i,1), floating_bars(i,1)+L(i)], [floating_bars(i,2) + curr_thickness, floating_bars(i,2) + curr_thickness], 'r')
else
plot([floating_bars(i,1), floating_bars(i,1)+L(i)], [floating_bars(i,2) + curr_thickness, floating_bars(i,2) + curr_thickness], 'b')
end
curr_thickness = curr_thickness + 0.05;
hold on % Make sure that plotting the current floating bar does not overwrite previous float bars that have already been plotted
end
end
ylim([ -10 30]) % Set the y-axis limits so that you can see more clearly the floating bars that would have rested right on the x-axis (y = 0)
Output:
How Do I Do This With the barh Function?
The short answer is that you'd have to modify the function manually. Someone has already done this with one of the bar graph plotting functions provided by MATLAB, bar3. The logic implemented in this modified bar3 function can be re-applied for your purposes if you read their barNew.m function and tweak it a bit. If you'd like a pointer as to where to start, I'd suggest looking at how they specify z-axis minimum and maximums for their floating bars on the plot, and apply that same logic to specify x-axis minimum and maximums for your floating bars in your 2D case.
I hope this helps, happy coding! :)
I explain here my approach to generate these type of graphs. Not sure if it is the best but it works and there is no need to do anything manually. I came up with this solution based on the following Vladislav Martin's explained fact: "The y-coordinates in this array only serve to distinguish Array1, Array2, and so on from each other".
My original arrays are:
Array4=[Nan....;20;21;22;23;24;..........60]
Array3=[Nan....;20;21;22;23;24;..........60]
Array2=[0;1;2;3;4;5;6;Nan;Nan;Nan;Nan;17;18;.....60]
Array1=[0;1;2;3;4;5;6;Nan;Nan;Nan;Nan;17;18;.....60]
x={'0m';'1m';'2m';'3m';'4m';....'60m'}
The values contained in these arrays make reference to the x-axis on the graph. In order to make the things more simple and to avoid having to code a function to determine the length for each discontinuity in the arrays, I replace these values for y-axis position values. Basically I give to Array1 y-axis position values of 0 and to Array2 0+0.02=0.02. To Array3 I give y-axis position values of 0.5 and to Array4 0.5+0.02=0.52. In this way, Array2 will be plotted on the graph closer to Array1 which will form the first group and Array4 closer to Array3 which will form the second group.
Datatable=table(Array1,Array2,Array3,Array4);
cont1=0;
cont2=0.02;
for col=1:2:size(Datatable,2)
col2=col+1;
for row=1:size(Datatable,1)
if isnan(Datatable{row,col})==0 % For first array in the group: If the value is not nan, I replace it for the corresponnding cont1 value
Datatable{row,col}=cont1;
end
if isnan(Datatable{row,col2})==0 % For second array in the group: If the value is not nan, I replace it for the corresponnding cont2 value
Datatable{row,col2}=cont2;
end
end
cont1=cont1+0.5;
cont2=cont2+0.5;
end
The result of the above code will be a table like the following:
And now I plot the Arrays using 2D floating lines:
figure
for array=1:2:size(Datatable,2)
FirstPair=cell2mat(table2cell(Datatable(:,array)));
SecondPair=cell2mat(table2cell(Datatable(:,array+1)));
hold on
plot(1:numel(x),FirstPair,'r','Linewidth',6)
plot(1:numel(x),SecondPair,'b','Linewidth',6)
hold off
end
set(gca,'xticklabel',x)
And this will generate the following graph:

How to detect patterns on a 1D array of measurements

I am developing an IA algorithm for a robot that needs to follow a line. The floor will be black, with a white line and there will be different marks that determine different types of "obstacles". I'm using a sensor that gives me an array of 8 measurements of the floor, as seen on the Figure 1 that give me an array of 8 measurements from 0 to 1000, where 0 there is no white and 1000 is totally white. In the examples bellow is a measurement of a white line in the middle of the sensor array and other cases.
int array[] = {50, 24, 9, 960, 1000, 150, 50, 45} // white line in the middle
int array2[] = {50, 24, 9, 960, 1000, 150, 50, 960} // white line in the middle and a square box on the right
int array3[] = {1000, 24, 9, 960, 1000, 150, 50, 40} // white line in the middle and a square box on the left
int array4[] = {1000, 980, 950, 0, 10, 980, 1000, 960} // black square box in the middle
Witch algorithms I could use to detect the patterns on the images below given this array of measurements? I do not want to use several "hardcoded" conditionals as templates, as I think it will not scale well. Im thinking on implementing a "peak counter" algorithm, but I do not know if it will work robust enough.
On the Figures we can see the different cases, the case I want to detect are the ones with the red circle.
Thanks!
How about doing something simple like treating each measurement like an N-dimensional vector. In your case N=8. Then, all you measurements are contained in a hypercube with sides up to length 1000. For N=8 there will be 256 corners. For each of your cases of interest, associate the hypercube corners that best match up to it. Note, some corners may not get associated. Then, for each measurement find its nearest associated hypercube corner. This tells you which case it is. You can mitigate errors by implementing some checks. For example, if the measurement is close to multiple corners (within some uncertainty threshold) then you label the measurement as being ambiguous and skip it.
It's easier to see this for the case of 3 measurements. The 8 corners of the cube could represent
[0,0,0] = no white
[0,0,1] = white on right
[0,1,0] = white in middle
[0,1,1] = white in middle and right
[1,0,0] = white on left
[1,0,1] = white on left and right
[1,1,0] = white on left and middle
[1,1,1] = all white
The case shown below is an ambiguous measurement in the middle.
(source: ctralie.com)

Resources