const courtStructure = [
{ class: 'legend-rect', shape: 'rect', x: 0, y: TLP + 38, width: 50, height: 8, fill: headerStyle.backgroundColor }, // rectangle behind legend
{ class: 'backboard', shape: 'line', x1: 22, x2: 28, y1: 3.75, y2: 3.75, stroke: hoopColor, opacity: hoopOpacity, strokeWidth: 0.5 }, // backboard
{ class: 'rim', shape: 'circle', r: 0.95, cx: 25, cy: 5.1, opacity: hoopOpacity, fill: hoopColor }, // the circle part of rim
{ class: 'back-iron', shape: 'rect', x: 24.625, y: 3.95, width: 0.75, height: 0.5, stroke: 0, opacity: hoopOpacity, fill: hoopColor } // back iron on rim
];
<rect
className='legend-rect'
x={0}
y={TLP + 38}
width={50}
height={8}
fill={headerStyle.backgroundColor}
/>
...
We have the courtStructure array of objects, and we would like to .map() over the array and create the SVG elements described. Example for the first rect is shown above. The keys in each object within courtStructure should be created as a field on the SVG element. The shape determines the element type.
The hardest part of achieving this seems to be:
creating the correct element (rect, line, circle, etc.)
handling the fact that different objects have different keys / parameters for the SVG
Is this possible to do?
For each object extract the properties that need "name mapping", e.g. shape, class, etc. The remaining properties are kept in a single object and passed to React as spread attributes.
You can then create the component via dynamic tags or directly via React.createElement:
const components = courtStructure.map(
({shape: Shape, class: className, ...props}) => {
return <Shape className={className} {...props} />
// or
return React.createElement(Shape, {className, ...props})
}
)
Also see
React docs - Choosing a type at runtime
I would probably change how the object structure is set up to separate the shape from the actual attributes, and make the keys of the attributes match the attributes you pass to the element like this:
const courtStructure = [
{
shape: 'rect',
attributes: {
className: 'legend-rect',
x: 0,
y: TLP + 38,
width: 50,
height: 8,
fill: headerStyle.backgroundColor
}
}, // rectangle behind legend
...
];
This way you can map through the array and make a switch statement for the shape to decide what element to render, and destructure the attributes on the svg element. Something like this:
{courtStructure.map((element) => {
switch(element.shape) {
case 'rect':
return (
<rect {...element.attributes} />
);
case 'line':
return (
<line {...element.attributes} />
);
case 'circle':
return (
<circle {...element.attributes} />
);
}
})}
You could also obviously refactor this logic to its own Shape component to make it cleaner!
I'm trying to switch from a ResponsiveLine to a ResponsiveLineCanvas using Javascript library Nivo version 0.80.0 and React 18.2.0, but markers are just not shown.
Not sure what I am missing, so I created an example to reproduce the issue
https://codesandbox.io/embed/fast-leftpad-q6ypqr?fontsize=14&hidenavigation=1&theme=dark
It is sufficient to switch from ResponsiveLineCanvas to ResponsiveLine and the marker get shown.
From the docs I cannot guess if the feature is unsupported in ResponsiveLineCanvas. So, am I missing any configuration?
import React, { useEffect, useState } from "react";
import { ResponsiveLineCanvas } from "#nivo/line";
import { ResponsiveLine } from "#nivo/line";
const commonProperties = {
width: 900,
height: 400,
margin: { top: 20, right: 20, bottom: 60, left: 80 },
animate: true,
enableSlices: "x"
};
const App = () => (
<div style={{ height: 600 }}>
<ResponsiveLineCanvas
{...commonProperties}
data={[
{
id: "Id of serie",
data: [
{ x: 0, y: 0.2 },
{ x: 1, y: 0.3 },
{ x: 2, y: 0.5 },
{ x: 3, y: 0.4 },
{ x: 4, y: 0.3 },
{ x: 5, y: 0.5 },
{ x: 6, y: 0.3 },
{ x: 7, y: 0.1 }
]
}
]}
markers={[
{
axis: "x",
value: 2,
lineStyle: { stroke: "#6aa84f", strokeWidth: 3, opacity: 0.95 },
legend: "Budget line"
}
]}
layers={[
"grid",
"axes",
"areas",
"lines",
"points",
"slices",
"mesh",
"legends",
"markers"
]}
enableGridX={false}
colors={["rgb(97, 205, 187)", "rgb(244, 117, 96)"]}
xScale={{
type: "linear"
}}
yScale={{
type: "linear",
stacked: false,
min: 0,
max: 1
}}
enableArea={true}
areaOpacity={1}
enableSlices={false}
useMesh={true}
crosshairType="cross"
/>
</div>
);
export default App;
Looking at the source code, it's clear that support for markers has not been implemented in the LineCanvas and ResponsiveLineCanvas components. There is no mention of markers anywhere in the component source. The markers prop is not included in the destructuring assignment so that prop will be ignored and have no effect.
As for the layers prop, this Canvas version goes through a bunch of if statements to check for known layer types. "marker" is not one of these types. There is no else statement that lets you know if a provided layer was invalid, it just doesn't do anything.
The supported values of the layers prop, per the source code, are:
"grid"
"axes"
"areas"
"lines"
"points"
"mesh"
"legends"
custom functions
On the other hand, the SVG-based Line and ResponsiveLine components do use the markers prop and support layers=["markers"]. You can see here how the markers prop is passed off to a CartesianMarkers component from the #nivo/core package and the resulting element is stored in the layerById dictionary.
I have a dataset (which contains both the data and the label) with the size of [299,13], and the model keeps outputting / predicting the same value. This is a binary classification task. How would I make my model predict values which are not constantly the same?
Here is the code (with some dummy data):
var Dataset = tf.tensor([[1,0.491821360184978,9,314,0.504585169147173,542,1231,3213,1,0.267304071302649,3,0.615917680092409,0],
[0,0.72959029133292,3,758,0.402582737085955,400,1788,4599,0,0.532702887951197,4,0.18630897965037,1],
[1,0.198764110760428,5,787,0.65507860022684,887,192,4831,1,0.739456077544426,3,0.100068056951143,1],
[0,0.583574833590476,5,596,0.933996451580092,631,331,811,0,0.258445986493932,7,0.811276729811182,0],
[1,0.701499878184206,8,854,0.0326334179806069,845,470,4930,1,0.825469683527519,1,0.448086959665654,1],
[0,0.954482878414911,2,468,0.736300149681564,557,3110,739,0,0.325783042694677,5,0.43488580142501,1],
[1,0.384845877769,2,662,0.265402742189238,649,384,1158,1,0.484884260891815,2,0.915444292219105,0],
[1,0.379266474923531,9,551,0.275982850450116,1022,3329,1413,1,0.237295089390298,4,0.817104709627837,1],
[1,0.691365367558705,8,549,0.479627221800976,796,3381,495,1,0.37129382411555,9,0.332832739155564,1],
[0,0.433042848178662,5,529,0.545178403950882,842,4768,506,0,0.386370525896832,9,0.189942077251933,0],
[1,0.611272282663452,4,823,0.737901576655264,839,2724,1787,1,0.365032317656007,6,0.884073622694046,0],
[0,0.0084315409129881,5,352,0.76858549557176,476,685,4796,0,0.302944943656102,1,0.849655932794213,1],
[0,0.977380232874908,6,701,0.588833228576897,999,2897,3325,0,0.418024491281536,2,0.631872118440871,1],
[1,0.419601058571829,10,384,0.0157052616592944,1009,4438,113,1,0.909015627566542,1,0.0297684897733232,0],
[0,0.739471449044276,4,836,0.0430176780439737,1030,1456,3932,0,0.331426481315121,6,0.734008754824423,0],
[1,0.00209807072438295,4,352,0.499622407429238,418,1912,4452,1,0.727130871883893,8,0.157427964683612,0],
[1,0.956533819923862,10,681,0.196708599930969,829,4562,1718,1,0.233193195569506,7,0.60582783922237,0],
[1,0.504637155233183,8,809,0.608861975627751,717,130,4194,1,0.134197560919101,6,0.375188428842507,0],
[0,0.747363884375055,1,522,0.868234577182028,849,3529,1192,0,0.0322641640468155,5,0.185973206518818,0],
[0,0.244142898027225,10,402,0.0280582030746698,315,3576,3882,0,0.724916254371562,8,0.062229775169706,1],
[0,0.858414851618448,8,459,0.367325906336267,616,930,3892,0,0.177388425930446,10,0.859824526007041,1],
[1,0.921555604905976,2,863,0.821166873626313,528,1624,1289,1,0.366243396916411,5,0.453840754701258,1],
[1,0.171321120311715,1,524,0.177251413832862,468,1608,3123,1,0.192861821442111,8,0.122983286410146,0],
[0,0.539946042901786,6,692,0.817780349862711,392,1053,4891,0,0.409578972921785,3,0.0453862502541893,1],
[1,0.996848843212564,5,549,0.877740438211017,762,3046,843,1,0.888578696082088,8,0.877971306478434,1],
[0,0.218116987741582,3,655,0.240496962520226,407,1001,1474,0,0.976212355833712,2,0.936396547703282,1]])
var x = Dataset.slice([0, 0], [-1, 12])
var y = Dataset.slice([0, 12], [-1, 1]) y = y.cast('int32').reshape([-1]).oneHot(2) y.print()
const model = tf.sequential({
layers: [
tf.layers.dense({ inputShape: [12], units: 12, activation: "relu6" }),
tf.layers.dense({ units: 56, activation: "tanh" }),
tf.layers.dense({ units: 28, activation: "tanh" }),
tf.layers.dense({ units: 14, activation: "sigmoid" }),
tf.layers.dense({ units: 58, activation: "tanh" }),
tf.layers.dense({ units: 2, activation: "softmax" })
] }) model.summary()
model.compile({
optimizer: tf.train.adam(),
loss: 'categoricalCrossentropy',
metrics: ['accuracy'], });
model.fit(x, y, { batchSize: 3, epochs: 10, shuffle: true }).then(h => {
console.log("Training Complete")
var predictions = model.predict(x)
predictions.print() });
299 samples with 13 features. That might not be enough for model to generalize. In your hidden layers you use tanh, and sigmoid. I suggest using relu. Also you one-hot-encoding your labels to use softmax, that's understandable but you might want to use sigmoid.
If you use sigmoid without one-hot-encoding, then you will have a chance to set some threshold depending on your business problem.
tf.layers.dense({ units: 1, activation: "sigmoid" })
Let's say you set 0.5 threshold for predictions, means if your prediction is bigger than 0.5 then it will belong to second class. But you can adjust it to, say 0.4, to see what happens. You can conclude it by interpreting AUC-ROC curve.
Another thing is about features, they are not scaled properly:
[1,0.00209807072438295,4,352,0.499622407429238,418,1912,4452,1,0.727130871883893,8,0.157427964683612,0]
If they are not scaled properly in a range, then model can give more importance to certain features than the others, or some unexpected behaviors can happen.
I had the same problem. Model is trained but it always predicts the same value. I don't know the exact principle, but I first trained model with fake data and then trained with normal data again, and this problem was solved.
I think it was initialized by training with fake data at first.
I will add example code.
var fake_xs = tf.zeros([10, 7, 7, 256]);
var fake_ys = tf.zeros([10]);
newModel.current.fit(
fake_xs,
fake_ys, {
epochs: 5,
callbacks: {
onEpochEnd: async (epoch, logs) => {
setLoss(logs.loss.toFixed(5));
console.log("LOSS: " + logs.loss.toFixed(5));
},
},
});
const history = await newModel.fit(
datasetForTraining.xs,
datasetForTraining.ys,
{
epochs: epochNum,
batchSize: 16,
callbacks: {
onEpochEnd: async (epoch, logs) => {
setLoss(logs.loss.toFixed(5));
console.log("LOSS: " + logs.loss.toFixed(5));
},
},
}
I'm using DeckGL with React to display some data on an OpenStreetMap.
I'm planning on implementing some filters to be able to display different views on the data I have.
My main problem is, that I can't figure out how to refresh the data representing layer after filtering the data array.
I saw a bunch of people creating a DeckGL-Object in JavaScript, and then using this, to call deck.setProps() but I couldn't figure out how to render this DeckGL-Object by using react.
This is my app.js:
export default function App({showBorder = false, onTilesLoad = null}) {
layers = [
/**
* TileLayer ist ein Layer aus Open-Streetmap-Tiles (Anzeigen der Karte)
*/
new TileLayer({
data: [/*OSM TileServer*/],
maxRequests: 20,
pickable: true,
onViewportLoad: onTilesLoad,
autoHighlight: showBorder,
highlightColor: [60, 60, 60, 40],
minZoom: 0,
maxZoom: 19,
tileSize: 512 / devicePixelRatio,
renderSubLayers: (props) => {
const {
bbox: {west, south, east, north}
} = props.tile;
return [
new BitmapLayer(props, {
data: null,
image: props.data,
bounds: [west, south, east, north]
}),
showBorder &&
new PathLayer({
id: `${props.id}-border`,
visible: props.visible,
data: [
[
[west, north],
[west, south],
[east, south],
[east, north],
[west, north]
]
],
getPath: (d) => d,
getColor: [255, 0, 0],
widthMinPixels: 4
})
];
}
}),
new HexagonLayer({
id: 'hexagon-layer',
data: /*JsonDataArray*/,
pickable: true,
extruded: true,
radius: 2000,
elevationRange: [25, 500],
elevationScale: 200,
autoHighlight: true,
opacity: 0.2,
colorRange: [
[255, 255, 204],
[199, 233, 180],
[127, 205, 187],
[65, 182, 196],
[44, 127, 184],
[37, 52, 148]
],
getElevationHeight: () => 500,
getPosition: (d) => d.coordinates,
})
];
return (
<DeckGL
layers={layers}
views={new MapView({repeat: true})}
initialViewState={INITIAL_VIEW_STATE}
controller={true}
/>
);
}
Obviously is there a little bit more to my app.js but I don't think the missing parts are important since I just wanna know how I can refresh a layer.
I also have a index.html but I don't think it's content is really relevant either since it's only use is to call the App function to render the layers.
I just can't find out what to do, to cause a reload of the HexagonLayer.
Thanks for your help in advance.
A good approach is using DataFilterExtension. GPU-based data
filtering, go this way if you care about performance. For the
moment there is a limitation of the extension for
HexagonLayer, but maybe using GPUGridLayer can help you in your
visualization also.
I.e: let's say you want to filter your qualitative data.
filterRange needs numeric bounds (which defines whether an object
should be rendered), so you can set your bounds as [1, 1] and
check if some object matches with you current filter condition, if
matches, getFilterValue gets 1, so that object will be rendered,
otherwise, not rendered:
const [filterCondition, setFilter] = useState('');
useEffect(() => {
// dispatch some action to set the filter
setFilter('cities');
}, []);
new ScatterplotLayer({
...otherProps,
getFilterValue: object => object.properties.target === filterCondition ? 1 : 0,
filterRange: [1, 1],
extensions: [new DataFilterExtension({ filterSize: 1 })],
updateTriggers: {
// It's important to tell deck.gl when to update
getFilterValue: filterCondition
}
});
Otherwise updating you data array should be enough. That means a
CPU-based data filtering, if your data is not huge, it's okey.
Thanks to reactivity should be enough with something like this:
const [yourData, setData] = useState([]);
useEffect(() => {
// dispatch some action to set data
setData([newData]);
}, []);
const layers = [
new HexagonLayer({
...otherProps,
data: yourData
});
];
return (
<DeckGL
...otherProps,
layers={layers}
/>
);
P.D: deck.setProps() is recommended to use in a non-reactive environment
The first example shown on the react-spring transition page is wrong, the code does not correspond to the animation shown.
How could I achieve that same effect?, how can I get a delay between the input of each component and using spring easing?.
When I try this, all components are entered at the same time.
Use transition example
These examples in the documentation are just drafts to give you some overview. It is a shame that react-spring only provides more advanced animations and lacks some basic example.
Anyway. The most basic delay between elements can be achieved with the trail property of the transition.
const transitions = useTransition(items, item => item, {
from: { transform: "translate3d(0,-40px,0)", display: "inline-block" },
enter: { transform: "translate3d(0,0px,0)" },
leave: { transform: "translate3d(0,-40px,0)" },
trail: 100
});
You can use this parameter only for sequential delay. When more than one item added or removed from the array your transition based on.
https://codesandbox.io/s/new-bird-sztw9
In the first example they do not use this. They are supposed to add and remove the item to the list a little staggered. I try to reproduce it. This is the staggered add:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const handleClick = async () => {
if (items.length === 0) {
set([3]);
await sleep(1000);
set([2, 3]);
await sleep(1000);
set([2, 3, 4]);
await sleep(1000);
set([1, 2, 3, 4]);
} ...
https://codesandbox.io/s/shy-sky-56lrw
This is closer to the example. But there are slight bumps when the mounts/unmounts of the transitions happen.
I hope it helps.
As a side note. I checked the source code of the react-spring page and they are cheating. The first example is do not even use transitions for the smooth animation. It uses interpolate to orchestrate the movement of each number. This is some advanced use with special components.
<RewindSpring>
{x => (
<>
<animated.div
style={{
opacity: x.interpolate({range: [0.75, 1.0], output: [0, 1]}),
transform: x.interpolate({range: [0.75, 1.0], output: [-40, 0], extrapolate: 'clamp'}).interpolate(x => `translate3d(0,${x}px,0)`)
}}
>
1
</animated.div>
<animated.div
style={{
opacity: x.interpolate({range: [0.25, 0.5], output: [0, 1]}),
transform: x.interpolate({range: [0.25, 0.5], output: [-40, 0], extrapolate: 'clamp'}).interpolate(x => `translate3d(0,${x}px,0)`)
}}
>
2
</animated.div>
<animated.div
style={{
opacity: x.interpolate({range: [0.0, 0.25], output: [0, 1]}),
transform: x.interpolate({range: [0.0, 0.25], output: [-40, 0], extrapolate: 'clamp'}).interpolate(x => `translate3d(0,${x}px,0)`)
}}
>
3
</animated.div>
<animated.div
style={{
opacity: x.interpolate({range: [0.5, 0.75], output: [0, 1]}),
transform: x.interpolate({range: [0.5, 0.75], output: [-40, 0], extrapolate: 'clamp'}).interpolate(x => `translate3d(0,${x}px,0)`)
}}
>
4
</animated.div>
</>
)}
</RewindSpring>