Im coding a Paint version for Minecraft with the CC Tweaked Mod
The Problem is i give my program an array and the program follows the order of the array one after the other.
That means if i draw something in the top left and then bottom right and then i fill everything else it will follow this order (which isnt very efficient)
I have an array called output
Here is how the array could look like
[
{ x: 0, y: 0, color: 12 },
{ x: 1, y: 0, color: 3 },
{ x: 2, y: 0, color: 5 },
{ x: 0, y: 1, color: 8 },
{ x: 1, y: 1, color: 10 },
{ x: 2, y: 1, color: 11 },
{ x: 0, y: 2, color: 12 },
{ x: 2, y: 2, color: 3 },
{ x: 1, y: 2, color: 14 }
]
The array comes from this "drawing"(ignore the arrows for now)
Now the question
How can i get from the first array to an array that looks like this
[
{ x: 0, y: 0, color: 12 },
{ x: 1, y: 0, color: 3 },
{ x: 2, y: 0, color: 5 },
{ x: 2, y: 1, color: 11 },
{ x: 1, y: 1, color: 10 },
{ x: 0, y: 1, color: 8 },
{ x: 0, y: 2, color: 12 },
{ x: 1, y: 2, color: 14 }
{ x: 2, y: 2, color: 3 },
]
(See how it follows the arrows?)
This would be much faster.
It is possibles that some squares are not filled with any color. Idk how important that might be
If important these are the colorcodes
const LISTOFCOLORS = {
white: 1,
orange: 2,
magenta: 3,
dodgerblue: 4,
yellow: 5,
lime: 6,
pink: 7,
gray: 8,
lightgray: 9,
cyan: 10,
purple: 11,
blue: 12,
SaddleBrown: 13,
green: 14,
red: 15,
black: 16
}
If you are only reversing the 3 - 6 entries, you could create a new array from slices of the old array using slice() and reverse the specified entries using reverse().
const rowByRow = [
{ x: 0, y: 0, color: 12 },
{ x: 1, y: 0, color: 3 },
{ x: 2, y: 0, color: 5 },
{ x: 0, y: 1, color: 8 },
{ x: 1, y: 1, color: 10 },
{ x: 2, y: 1, color: 11 },
{ x: 0, y: 2, color: 12 },
{ x: 2, y: 2, color: 3 },
{ x: 1, y: 2, color: 14 }
];
const result = [
...rowByRow.slice(0, 3),
...rowByRow.slice(3, 6).reverse(), // reverse 3 - 6 entries
...rowByRow.slice(6, 9)
];
console.log(result);
#axtck Thank you very much. I ended up not using slice but the "slicing the array in multiple arrays and work from there" part i got from your post
i ended up with this
const arr = [
{ x: 1, y: 4, color: 12 },
{ x: 2, y: 4, color: 12 },
{ x: 2, y: 3, color: 12 },
{ x: 2, y: 2, color: 12 },
{ x: 2, y: 1, color: 12 },
{ x: 0, y: 0, color: 12 },
{ x: 1, y: 0, color: 12 },
{ x: 1, y: 1, color: 12 },
{ x: 4, y: 1, color: 12 },
{ x: 3, y: 2, color: 12 },
{ x: 1, y: 3, color: 12 },
{ x: 0, y: 3, color: 12 },
{ x: 0, y: 1, color: 12 },
{ x: 0, y: 2, color: 12 },
{ x: 1, y: 2, color: 12 },
{ x: 3, y: 4, color: 12 },
{ x: 4, y: 4, color: 12 },
{ x: 4, y: 0, color: 12 },
{ x: 3, y: 0, color: 12 },
{ x: 2, y: 0, color: 12 },
{ x: 3, y: 1, color: 12 },
{ x: 4, y: 2, color: 12 },
{ x: 4, y: 3, color: 12 },
{ x: 0, y: 4, color: 12 },
{ x: 3, y: 3, color: 12 }
]
const ArrayOfArrays = []
const dimension = 5
for (let i = 0; i < dimension; i++) {
let array = []
for (let j = 0; j < arr.length; j++) {
if (i == arr[j].y) {
array.push(arr[j])
}
}
ArrayOfArrays.push(i % 2 === 0 ?
array.sort(function (a, b) {
return a.x - b.x;
}) : array.sort(function (a, b) {
return b.x - a.x;
}))
}
console.log(ArrayOfArrays)
The output would be
[
[
{ x: 0, y: 0, color: 12 },
{ x: 1, y: 0, color: 12 },
{ x: 2, y: 0, color: 12 },
{ x: 3, y: 0, color: 12 },
{ x: 4, y: 0, color: 12 }
],
[
{ x: 4, y: 1, color: 12 },
{ x: 3, y: 1, color: 12 },
{ x: 2, y: 1, color: 12 },
{ x: 1, y: 1, color: 12 },
{ x: 0, y: 1, color: 12 }
],
[
{ x: 0, y: 2, color: 12 },
{ x: 1, y: 2, color: 12 },
{ x: 2, y: 2, color: 12 },
{ x: 3, y: 2, color: 12 },
{ x: 4, y: 2, color: 12 }
],
[
{ x: 4, y: 3, color: 12 },
{ x: 3, y: 3, color: 12 },
{ x: 2, y: 3, color: 12 },
{ x: 1, y: 3, color: 12 },
{ x: 0, y: 3, color: 12 }
],
[
{ x: 0, y: 4, color: 12 },
{ x: 1, y: 4, color: 12 },
{ x: 2, y: 4, color: 12 },
{ x: 3, y: 4, color: 12 },
{ x: 4, y: 4, color: 12 }
]
]
notice how the x value goes up and down
I am adding data to charts like this
const data = [
["2020-05-22 14:20:22", "173.9"],
["2020-05-22 14:20:40", "175.3"],
["2020-05-22 14:20:58", "172.4"]
]
function stringToDate(s) {
s = s.split(/[-: ]/);
return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5]);
}
for(var key in data)
{
var xTime = stringToDate(data[key][0]);
var yVal = parseFloat(data[key][1]);
series.add({ x: xTime.getTime() - dateOrigin.getTime(), y: yVal})
}
How do I show custom label to it, For example I want to show full date for above line series and also for other scatter charts , I want to show custom label like below.
series.add({ x: xTime.getTime() - dateOrigin.getTime(), y: yVal , label : "my own text" })
To show a full date for a series using a DateTime axis you can take a look at my previously posted answer: https://stackoverflow.com/a/59839354/6198227 The sort version of it is to define a format options based on Intl.DateTimeFormat when defining the axis tick strategy for a axis.
Custom labels can be done by creating custom ticks. The text inside the tick can be defined with a text formatter set by Axis.setTextFormatter. The formatter function gets the position and the tick itself as parameters so those can be used to define the text inside the tick if that's needed.
const tick = lineSeries.axisX.addCustomTick()
.setGridStrokeLength(0)
.setTextFormatter(()=>'My Text')
.setValue(dataFrequency * 50)
See below snippet for a implementation of both custom DateTime formatting and the use of custom ticks. The snippet is based on DateTime Axis example from the LightningChart JS Interactive Examples.
LightningChart JS v1.3.1 example:
// Extract required parts from LightningChartJS.
const {
lightningChart,
AxisTickStrategies,
DataPatterns,
emptyFill,
emptyLine
} = lcjs
// Create a XY Chart.
const dateOrigin = new Date(2008, 0, 1)
const chart = lightningChart().ChartXY({
defaultAxisXTickStrategy: AxisTickStrategies.DateTime(
dateOrigin,
undefined,
{
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}
)
})
.setTitle('Customer Satisfaction')
chart.setPadding({ right: '5' })
// Add a progressive line series.
// Using the DataPatterns object to select the horizontalProgressive pattern for the line series.
const lineSeries = chart.addLineSeries({ dataPattern: DataPatterns.horizontalProgressive })
.setName('Customer Satisfaction')
// Generate some points using for each month
const dataFrequency = 30 * 24 * 60 * 60 * 1000
// Setup view nicely.
chart.getDefaultAxisY()
.setScrollStrategy(undefined)
.setInterval(0, 100)
.setTitle('Satisfaction %')
// Data for the plotting
const satisfactionData = [
{ x: 0, y: 0 },
{ x: 1, y: 8 },
{ x: 2, y: 12 },
{ x: 3, y: 18 },
{ x: 4, y: 22 },
{ x: 5, y: 32 },
{ x: 6, y: 40 },
{ x: 7, y: 48 },
{ x: 8, y: 50 },
{ x: 9, y: 54 },
{ x: 10, y: 59 },
{ x: 11, y: 65 },
{ x: 12, y: 70 },
{ x: 13, y: 68 },
{ x: 14, y: 70 },
{ x: 15, y: 69 },
{ x: 16, y: 66 },
{ x: 17, y: 65.4 },
{ x: 18, y: 64 },
{ x: 19, y: 65 },
{ x: 20, y: 63.5 },
{ x: 21, y: 62 },
{ x: 22, y: 61.2 },
{ x: 23, y: 63 },
{ x: 24, y: 61 },
{ x: 25, y: 62 },
{ x: 26, y: 62 },
{ x: 27, y: 60 },
{ x: 28, y: 57.8 },
{ x: 29, y: 58 },
{ x: 30, y: 61 },
{ x: 31, y: 59 },
{ x: 32, y: 63 },
{ x: 33, y: 61 },
{ x: 34, y: 61.8 },
{ x: 35, y: 62 },
{ x: 36, y: 59.9 },
{ x: 37, y: 58 },
{ x: 38, y: 60 },
{ x: 39, y: 63 },
{ x: 40, y: 59.5 },
{ x: 41, y: 62.5 },
{ x: 42, y: 59.7 },
{ x: 43, y: 57 },
{ x: 44, y: 61 },
{ x: 45, y: 59 },
{ x: 46, y: 61 },
{ x: 47, y: 65 },
{ x: 48, y: 62 },
{ x: 49, y: 60 },
{ x: 50, y: 58 },
{ x: 51, y: 59 },
{ x: 52, y: 61 },
{ x: 53, y: 64 },
{ x: 54, y: 65.5 },
{ x: 55, y: 67 },
{ x: 56, y: 68 },
{ x: 57, y: 69 },
{ x: 58, y: 68 },
{ x: 59, y: 69.5 },
{ x: 60, y: 69.9 },
{ x: 61, y: 68.5 },
{ x: 62, y: 67 },
{ x: 63, y: 65 },
{ x: 64, y: 63 },
{ x: 65, y: 60 },
{ x: 66, y: 61.6 },
{ x: 67, y: 62 },
{ x: 68, y: 61 },
{ x: 69, y: 60 },
{ x: 70, y: 63.3 },
{ x: 71, y: 62.7 },
{ x: 72, y: 64.3 },
{ x: 73, y: 63 },
{ x: 74, y: 61.2 },
{ x: 75, y: 60 },
{ x: 76, y: 61 },
{ x: 77, y: 64 },
{ x: 78, y: 61.9 },
{ x: 79, y: 61 },
{ x: 80, y: 58 },
{ x: 81, y: 59 },
{ x: 82, y: 60.5 },
{ x: 83, y: 61 },
{ x: 84, y: 63 },
{ x: 85, y: 64.5 },
{ x: 86, y: 65 },
{ x: 87, y: 66.2 },
{ x: 88, y: 64.9 },
{ x: 89, y: 63 },
{ x: 90, y: 62 },
{ x: 91, y: 63 },
{ x: 92, y: 61.8 },
{ x: 93, y: 62 },
{ x: 94, y: 63 },
{ x: 95, y: 64.2 },
{ x: 96, y: 63 },
{ x: 97, y: 61 },
{ x: 98, y: 59.7 },
{ x: 99, y: 61 },
{ x: 100, y: 58 },
{ x: 101, y: 59 },
{ x: 102, y: 58 },
{ x: 103, y: 58 },
{ x: 104, y: 57.5 },
{ x: 105, y: 59.2 },
{ x: 106, y: 60 },
{ x: 107, y: 61.9 },
{ x: 108, y: 63 },
{ x: 109, y: 64.1 },
{ x: 110, y: 65.9 },
{ x: 111, y: 64 },
{ x: 112, y: 65 },
{ x: 113, y: 62 },
{ x: 114, y: 60 },
{ x: 115, y: 58 },
{ x: 116, y: 57 },
{ x: 117, y: 58.2 },
{ x: 118, y: 58.6 },
{ x: 119, y: 59.3 },
{ x: 120, y: 61 }
]
// Adding points to the series
lineSeries.add(satisfactionData.map((point) => ({ x: point.x * dataFrequency, y: point.y })))
// Show the customized result table for each point
lineSeries.setResultTableFormatter((builder, series, xValue, yValue) => {
return builder
.addRow('Customer Satisfaction')
.addRow(series.axisX.formatValue(xValue))
.addRow(yValue.toFixed(2) + "%")
})
const tick = lineSeries.axisX.addCustomTick()
.setGridStrokeLength(0)
.setTextFormatter(()=>'My Text')
.setValue(dataFrequency * 50)
<script src="https://unpkg.com/#arction/lcjs#2.2.1/dist/lcjs.iife.js"></script>
Update for LightningChart JS v3.4.0
DateTime axis formatting options have changed a little bit, there are more options to format based on the zoom level. And setResultTableFormatter has been renamed to setCursorResultTableFormatter.
const formatting = {year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric'}
chart.getDefaultAxisX().setTickStrategy(AxisTickStrategies.DateTime, (styler)=>
styler.setDateOrigin(dateOrigin)
.setFormattingDay(formatting, formatting, formatting)
.setFormattingDecade(formatting, formatting, formatting)
.setFormattingHour(formatting, formatting, formatting)
.setFormattingMilliSecond(formatting, formatting, formatting)
.setFormattingMinute(formatting, formatting, formatting)
.setFormattingMonth(formatting, formatting, formatting)
.setFormattingSecond(formatting, formatting, formatting)
.setFormattingWeek(formatting, formatting, formatting)
.setFormattingYear(formatting, formatting, formatting)
)
LightningChart JS v3.4.0 example:
// Import LightningChartJS
const {
lightningChart,
AxisTickStrategies,
DataPatterns,
emptyFill,
emptyLine
} = lcjs
// Create a XY Chart.
const dateOrigin = new Date(2008, 0, 1)
const chart = lightningChart().ChartXY()
.setTitle('Customer Satisfaction')
const formatting = {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}
chart.getDefaultAxisX().setTickStrategy(AxisTickStrategies.DateTime, (styler) =>
styler.setDateOrigin(dateOrigin)
.setFormattingDay(formatting, formatting, formatting)
.setFormattingDecade(formatting, formatting, formatting)
.setFormattingHour(formatting, formatting, formatting)
.setFormattingMilliSecond(formatting, formatting, formatting)
.setFormattingMinute(formatting, formatting, formatting)
.setFormattingMonth(formatting, formatting, formatting)
.setFormattingSecond(formatting, formatting, formatting)
.setFormattingWeek(formatting, formatting, formatting)
.setFormattingYear(formatting, formatting, formatting)
)
chart.setPadding({
right: '5'
})
// Add a progressive line series.
// Using the DataPatterns object to select the horizontalProgressive pattern for the line series.
const lineSeries = chart.addLineSeries({
dataPattern: DataPatterns.horizontalProgressive
})
.setName('Customer Satisfaction')
// Generate some points using for each month
const dataFrequency = 30 * 24 * 60 * 60 * 1000
// Setup view nicely.
chart.getDefaultAxisY()
.setScrollStrategy(undefined)
.setInterval(0, 100)
.setTitle('Satisfaction %')
// Data for the plotting
const satisfactionData = [
{ x: 0, y: 0 },
{ x: 1, y: 8 },
{ x: 2, y: 12 },
{ x: 3, y: 18 },
{ x: 4, y: 22 },
{ x: 5, y: 32 },
{ x: 6, y: 40 },
{ x: 7, y: 48 },
{ x: 8, y: 50 },
{ x: 9, y: 54 },
{ x: 10, y: 59 },
{ x: 11, y: 65 },
{ x: 12, y: 70 },
{ x: 13, y: 68 },
{ x: 14, y: 70 },
{ x: 15, y: 69 },
{ x: 16, y: 66 },
{ x: 17, y: 65.4 },
{ x: 18, y: 64 },
{ x: 19, y: 65 },
{ x: 20, y: 63.5 },
{ x: 21, y: 62 },
{ x: 22, y: 61.2 },
{ x: 23, y: 63 },
{ x: 24, y: 61 },
{ x: 25, y: 62 },
{ x: 26, y: 62 },
{ x: 27, y: 60 },
{ x: 28, y: 57.8 },
{ x: 29, y: 58 },
{ x: 30, y: 61 },
{ x: 31, y: 59 },
{ x: 32, y: 63 },
{ x: 33, y: 61 },
{ x: 34, y: 61.8 },
{ x: 35, y: 62 },
{ x: 36, y: 59.9 },
{ x: 37, y: 58 },
{ x: 38, y: 60 },
{ x: 39, y: 63 },
{ x: 40, y: 59.5 },
{ x: 41, y: 62.5 },
{ x: 42, y: 59.7 },
{ x: 43, y: 57 },
{ x: 44, y: 61 },
{ x: 45, y: 59 },
{ x: 46, y: 61 },
{ x: 47, y: 65 },
{ x: 48, y: 62 },
{ x: 49, y: 60 },
{ x: 50, y: 58 },
{ x: 51, y: 59 },
{ x: 52, y: 61 },
{ x: 53, y: 64 },
{ x: 54, y: 65.5 },
{ x: 55, y: 67 },
{ x: 56, y: 68 },
{ x: 57, y: 69 },
{ x: 58, y: 68 },
{ x: 59, y: 69.5 },
{ x: 60, y: 69.9 },
{ x: 61, y: 68.5 },
{ x: 62, y: 67 },
{ x: 63, y: 65 },
{ x: 64, y: 63 },
{ x: 65, y: 60 },
{ x: 66, y: 61.6 },
{ x: 67, y: 62 },
{ x: 68, y: 61 },
{ x: 69, y: 60 },
{ x: 70, y: 63.3 },
{ x: 71, y: 62.7 },
{ x: 72, y: 64.3 },
{ x: 73, y: 63 },
{ x: 74, y: 61.2 },
{ x: 75, y: 60 },
{ x: 76, y: 61 },
{ x: 77, y: 64 },
{ x: 78, y: 61.9 },
{ x: 79, y: 61 },
{ x: 80, y: 58 },
{ x: 81, y: 59 },
{ x: 82, y: 60.5 },
{ x: 83, y: 61 },
{ x: 84, y: 63 },
{ x: 85, y: 64.5 },
{ x: 86, y: 65 },
{ x: 87, y: 66.2 },
{ x: 88, y: 64.9 },
{ x: 89, y: 63 },
{ x: 90, y: 62 },
{ x: 91, y: 63 },
{ x: 92, y: 61.8 },
{ x: 93, y: 62 },
{ x: 94, y: 63 },
{ x: 95, y: 64.2 },
{ x: 96, y: 63 },
{ x: 97, y: 61 },
{ x: 98, y: 59.7 },
{ x: 99, y: 61 },
{ x: 100, y: 58 },
{ x: 101, y: 59 },
{ x: 102, y: 58 },
{ x: 103, y: 58 },
{ x: 104, y: 57.5 },
{ x: 105, y: 59.2 },
{ x: 106, y: 60 },
{ x: 107, y: 61.9 },
{ x: 108, y: 63 },
{ x: 109, y: 64.1 },
{ x: 110, y: 65.9 },
{ x: 111, y: 64 },
{ x: 112, y: 65 },
{ x: 113, y: 62 },
{ x: 114, y: 60 },
{ x: 115, y: 58 },
{ x: 116, y: 57 },
{ x: 117, y: 58.2 },
{ x: 118, y: 58.6 },
{ x: 119, y: 59.3 },
{ x: 120, y: 61 }
]
// Adding points to the series
lineSeries.add(satisfactionData.map((point) => ({
x: point.x * dataFrequency,
y: point.y
})))
// Show the customized result table for each point
lineSeries.setCursorResultTableFormatter((builder, series, xValue, yValue) => {
return builder
.addRow('Customer Satisfaction')
.addRow(series.axisX.formatValue(xValue))
.addRow(yValue.toFixed(2) + "%")
})
const tick = lineSeries.axisX.addCustomTick()
.setGridStrokeLength(0)
.setTextFormatter(() => 'My Text')
.setValue(dataFrequency * 50)
<script src="https://unpkg.com/#arction/lcjs#3.4.0/dist/lcjs.iife.js"></script>
I am trying to draw a plot with multiple factors. I hope these different factors are distinguished by color, size, and shape of the scatter. An example of this kind of plot is here https://github.com/slfan2013/tempPlot/blob/master/Rplot.png.
I'd like to use a javascript library to draw a similar plot. I usually use plotly.js to draw plots. But I think plotly can only handle one factor at a time (different colors). My question is can plotly handle multiple (nested) factors in one single plot (like color, size, and shape)? If not, if there is any javascript library can achieve these? How about CanvasJS?
#### EDIT.
I understand how to draw scatter with different color and different size (shape, etc) on the same plot. I just would like to have a multiple-factor legend on the plot, so that if I click "red", for example, then the red scatters would hide no matter what size it is AND if I click size "big", big scatters would hide no matter what color it is.
Thanks!
This can be done in CanvasJS using scatter chart and by controlling markerType and markerSize. Check the example shown below.
Refer these pages for markerType and markerSize.
http://canvasjs.com/docs/charts/chart-options/data/markertype/
http://canvasjs.com/docs/charts/chart-options/data/markersize/
var chart = new CanvasJS.Chart("chartContainer",
{
title: {
text: "Scatter Chart with Different Marker Types"
},
legend: {
horizontalAlign: "right",
verticalAlign: "center"
},
data: [
{
type: "scatter",
showInLegend: true,
legendText: "Circle",
dataPoints: [
{ x: 1, y: 91, markerSize: 10 },
{ x: 2, y: 75, markerSize: 20 },
{ x: 3, y: 70, markerSize: 30 },
{ x: 4, y: 85, markerSize: 40 },
{ x: 5, y: 75, markerSize: 50 }
]
},
{
type: "scatter",
markerType: "square", //default "circle"
showInLegend: true,
legendText: "Square",
dataPoints: [
{ x: 1, y: 71, markerSize: 10 },
{ x: 2, y: 55, markerSize: 20 },
{ x: 3, y: 50, markerSize: 30 },
{ x: 4, y: 65, markerSize: 40 },
{ x: 5, y: 55, markerSize: 50 }
]
},
{
type: "scatter",
markerType: "triangle",
showInLegend: true,
legendText: "Triangle",
dataPoints: [
{ x: 1, y: 51, markerSize: 10 },
{ x: 2, y: 35, markerSize: 20 },
{ x: 3, y: 30, markerSize: 30 },
{ x: 4, y: 45, markerSize: 40 },
{ x: 5, y: 35, markerSize: 50 }
]
},
{
type: "scatter",
markerType: "cross",
showInLegend: true,
legendText: "Cross",
dataPoints: [
{ x: 1, y: 31, markerSize: 10 },
{ x: 2, y: 15, markerSize: 20 },
{ x: 3, y: 10, markerSize: 30 },
{ x: 4, y: 25, markerSize: 40 },
{ x: 5, y: 15, markerSize: 50 }
]
}
]
});
chart.render();
<script src="http://canvasjs.com/assets/script/canvasjs.min.js"></script>
<div id="chartContainer" style="height: 300px; width: 100%;"></div>
You would just need to define multiple traces and set the parameters for each trace individually.
trace0 is just the default settings
trace1 has a custom color
trace2 has a custom color and custom size
trace3 has a custom color, custom size and custom symbol
var trace0 = {
x: [1, 2, 3],
y: [1, 2, 3],
type: 'scatter',
mode:'markers'};
var trace1 = {
x: [1, 2, 3],
y: [2, 1.8, 1],
type: 'scatter',
mode:'markers',
marker: {
color: 'red'
}};
var trace2 = {
x: [1, 2, 3],
y: [2.8, 2.3, 1.2],
type: 'scatter',
mode:'markers',
marker: {
color: 'green',
size: [10, 15, 20]
}};
var trace3 = {
x: [1, 2, 3],
y: [3, 2.5, 1],
type: 'scatter',
mode:'markers',
marker: {
color: 'pink',
size: [10, 15, 20],
symbol: 303
}};
Plotly.plot('myDiv', [trace0, trace1, trace2, trace3])
<div id='myDiv'></div>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>