leeoniya / uPlot

📈 A small, fast chart for time series, lines, areas, ohlc & bars
MIT License
8.48k stars 370 forks source link

really like uPlot but how to get it to work properly #901

Open UltimateSolar opened 4 months ago

UltimateSolar commented 4 months ago

Hello,

pretty new to this, why does this not plot evenly X-D

on the X axis there shall be time dates like YYYY-MM-DD and time HH:MM:SS

on the Y axis there shall be watts

really like the zoom functionality and the dark theme :D

and the MIT licencing as it is used for Open Source

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Line Paths</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <link rel="stylesheet" href="css/uPlot.min.css">
        <style>
            body {
                margin: 0;
                background: #141619;
                color: #c7d0d9;
            }

            .uplot {
                margin-top: 30px;
            }

            .u-select {
                background: rgba(255,255,255,0.07);
            }
        </style>
    </head>
    <body>
        <script src="js/uPlot.iife.js"></script>
        <script>
            const { linear, stepped, bars, spline, spline2 } = uPlot.paths;
/*
            const data = [
                  // x-values (Unix timestamps)
                  [1077519305, 1177519305, 1377519305, 1477519305], 
                  // data series 1  
                  [0.54, 0.15, 3.27, 7.51],
                  // data series 2
                  [12.85, 13.21, 13.65, 14.01],
                  // data series 3
                  [0.52, 1.25, 0.75, 3.62]
            ];
*/
            const data = [
                  // x-values (Unix timestamps)
                  [1702213297, 1702213308, 1702213317, 1702213327, 1702213340, 1702213353, 1702213367, 1702213382, 1702213395, 1702213408, 1702213420, 1699939996, 1699940001, 1699940016, 1699940021, 1699940032, 1699940039, 1699940048, 1699940061, 1699940072, 1699940077, 1698645904, 1698645917, 1698645926, 1698645936, 1698645947, 1698645960, 1698645970, 1698645984, 1698645994, 1698646003], 
                  // data series 1  
                  [122, 122, 123, 128, 136, 146, 154, 159, 164, 170, 171, 159, 159, 158, 157, 158, 158, 159, 161, 163, 164, 35, 63, 68, 74, 37, 83, 74, 49, 62, 63], 
                  // data series 2
                  [12.85, 13.21, 13.65, 14.01],
                  // data series 3
                  [0.52, 1.25, 0.75, 3.62]
            ];

            // data[0].splice(22, 4, null, null, null, null);

            const lineInterpolations = {
                linear:     0,
                stepAfter:  1,
                stepBefore: 2,
                spline:     3,
            //  spline2:    4,
            };

            const drawStyles = {
                line:      0,
                bars:      1,
                points:    2,
                barsLeft:  3,
                barsRight: 4,
            };

            // generate bar builder with 60% bar (40% gap) & 100px max bar width
/*          const _bars60_100   = bars({size: [0.6, 100]});
            const _bars100Left  = bars({size: [1], align:  1});
            const _bars100Right = bars({size: [1], align: -1});
            const _stepBefore   = stepped({align: -1}); //, ascDesc: true
            const _stepAfter    = stepped({align:  1}); //, ascDesc: true
*/
            const _linear       = linear();
/*          const _spline       = spline(); */
        //  const _spline2      = spline2();

            function paths(u, seriesIdx, idx0, idx1, extendGap, buildClip) {
                let s = u.series[seriesIdx];
                let style = s.drawStyle;
                let interp = s.lineInterpolation;

                let renderer = (
                    style == drawStyles.line ? (
                        interp == lineInterpolations.linear     ? _linear :
                        interp == lineInterpolations.stepAfter  ? _stepAfter :
                        interp == lineInterpolations.stepBefore ? _stepBefore :
                        interp == lineInterpolations.spline     ? _spline :
                    //  interp == lineInterpolations.spline2    ? _spline2 :
                        null
                    ) :
                    style == drawStyles.bars ? (
                        _bars60_100
                    ) :
                    style == drawStyles.barsLeft ? (
                        _bars100Left
                    ) :
                    style == drawStyles.barsRight ? (
                        _bars100Right
                    ) :
                    style == drawStyles.points ? (
                        () => null
                    ) : () => null
                );

                return renderer(u, seriesIdx, idx0, idx1, extendGap, buildClip);
            }

            const palette = [
                '#7EB26D', // 0: pale green
                '#EAB839', // 1: mustard
                '#6ED0E0', // 2: light blue
                '#EF843C', // 3: orange
                '#E24D42', // 4: red
                '#1F78C1', // 5: ocean
                '#BA43A9', // 6: purple
                '#705DA0', // 7: violet
                '#508642', // 8: dark green
                '#CCA300', // 9: dark sand
            ];

            let cfgs = [
                {
                    title: "linear",
                    drawStyle: drawStyles.line,
                    lineInterpolation: lineInterpolations.linear,
                    stroke: "#7EB26D",
                },
            ];

            function makeChart(cfg) {
                let opts = {
                    width: 2048,
                    height: 600,
                    title: cfg.title,
                    cursor: {
                        points: {
                            size:   (u, seriesIdx)       => u.series[seriesIdx].points.size * 2.5,
                            width:  (u, seriesIdx, size) => size / 4,
                            stroke: (u, seriesIdx)       => u.series[seriesIdx].points.stroke(u, seriesIdx) + '90',
                            fill:   (u, seriesIdx)       => "#fff",
                        },
                        sync: {
                            key: 0,
                        }
                    },
                    scales: {
                        x: {
                            time: true,
                        //  range: [-10,110],
                        //  dir: -1,
                        },
                    },
                    axes: [
                        {
                            stroke: "#c7d0d9",
                        //  font: `12px 'Roboto'`,
                        //  labelFont: `12px 'Roboto'`,
                            grid: {
                                width: 1 / devicePixelRatio,
                                stroke: "#2c3235",
                            },
                            ticks: {
                                width: 1 / devicePixelRatio,
                                stroke: "#2c3235",
                            }
                        },
                        {
                            stroke: "#c7d0d9",
                        //  font: `12px 'Roboto'`,
                        //  labelFont: `12px 'Roboto'`,
                            grid: {
                                width: 1 / devicePixelRatio,
                                stroke: "#2c3235",
                            },
                            ticks: {
                                width: 1 / devicePixelRatio,
                                stroke: "#2c3235",
                            }
                        },
                    ],
                    series: [
                        {
                            label: "Time",
                        },
                        Object.assign({
                            label: "Watts",
                            width: 1 / devicePixelRatio,
                            drawStyle: drawStyles.points,
                            lineInterpolation: null,
                            paths,
                        }, {
                            drawStyle:         cfg.drawStyle,
                            lineInterpolation: cfg.lineInterpolation,
                            stroke:            cfg.stroke,
                            fill:              cfg.stroke + "1A",
                        }),
                    ],
                };

                return new uPlot(opts, data, document.body);
            }

            cfgs.forEach(cfg => {
                makeChart(cfg);
            });
        </script>
        <p>
        Array
(
    [0] => 2023-12-10 USB-QPIGS.log
    [1] => 2023-11-14 USB-QPIGS.log
    [2] => 2023-10-30 USB-QPIGS.log
)
$chart_data_string_date = [1702213297, 1702213308, 1702213317, 1702213327, 1702213340, 1702213353, 1702213367, 1702213382, 1702213395, 1702213408, 1702213420, 1699939996, 1699940001, 1699940016, 1699940021, 1699940032, 1699940039, 1699940048, 1699940061, 1699940072, 1699940077, 1698645904, 1698645917, 1698645926, 1698645936, 1698645947, 1698645960, 1698645970, 1698645984, 1698645994, 1698646003]$chart_data_string_watts = [122, 122, 123, 128, 136, 146, 154, 159, 164, 170, 171, 159, 159, 158, 157, 158, 158, 159, 161, 163, 164, 35, 63, 68, 74, 37, 83, 74, 49, 62, 63]      </p>
    </body>
</html>

thanks for uPlot

Edgepath commented 4 months ago

never mind got it to work with chart.js

YaminoYuki commented 2 months ago

A point of view .. uplot is much faster than chart.js ..so if you are considering to work with large data .. maybe you can re-give uplot a try

UltimateSolar commented 2 months ago

Hello Yamino,

yes indeed, when those solar energy chart dots accumulate over time (millions and millions) really need to workaround the mass of data 😃