I'm trying to plot some sine waves (code example in plain js here).

When freq is "low" (freq = 10 hz in that case), the plot is quite nice:

enter image description here

The problem is when I increase the freq (try to set var freq = 50 for example):

enter image description here

lots of ripples, it becomes distorted and not so good as plot. If I increment it more, even worse (var freq = 8030 for example is terrible). When I see those kind of graph on pro systems, they are displayed just fine.

How would you improve it? FFT, splines, whatever? Which is the right approch?

I don't really need accurancy (i.e. for waveform analysis or whatever), just plot it nicely (as in Desmos https://www.desmos.com/calculator/eodkjlywjh, for example).


2 Answers 2


For a given «visual accuracy», you need to sample the sine at a sufficient number of time-steps per period.

At some point the display pixel density will be to low to render a sine accurately.

For waveform editors (that usually have access to only a finite rate sampled waveform, not a continously defined trigonometric function), I assume that some practical approximation to the sinc(x) function is used to interpolate those samples to the desired density. There is still a question of what to do when the display is the limiting factor, rather than the input.

  • $\begingroup$ of course, but this doesn't mean we can't have a fancy display. i don't need accurancy for examine the waveform, just plot it nicely. this for example desmos.com/calculator/eodkjlywjh $\endgroup$
    – markzzz
    Commented Oct 22, 2020 at 19:49
  • $\begingroup$ @markzzz What Knut is saying is that your display, in this case 480 px wide, cannot make your function look nice without some kind of interpolation. $\endgroup$
    – Envidia
    Commented Oct 22, 2020 at 20:22
  • $\begingroup$ Well, that I noticed myself :) The question here is which kind of technique (interpolation or so) to use... $\endgroup$
    – markzzz
    Commented Oct 22, 2020 at 20:57
  • $\begingroup$ @markzzz That's up to you in weighing accuracy and potentially performance. If you can get away with a bicubic spline without any serious performance penalties then try something along those lines. Otherwise, something simpler like a linear interpolation might suffice. $\endgroup$
    – Envidia
    Commented Oct 22, 2020 at 21:13
  • $\begingroup$ If you view the display as a (crude) D/A converter, it is kind of like a sample&hold filtered pulse train converter, except that it supports simultaneous amplitude values. There is no single «right» when depicting a waveform that oscillates «fast» relative to pixel pitch. You might like a «full amplitude» sine of +/-1 to show full excursion in your plot, but Nyquist might disagree. $\endgroup$
    – Knut Inge
    Commented Nov 24, 2020 at 18:00

If you're really generating a pure sine, you know the amplitude and can force the peaks of a half-cycle to draw at the intended peak.

If the waveform is more complex, you can generate it at a sufficiently high sample rate. The issue with drawing is that you can't necessarily plot consecutive samples and still have enough of the waveform in view, horizontally, to see as much as you want. That's OK, you can consolidate multiple samples into a single pixel-wide space.

For instance, you can view 2000 samples in a 400-pixel-wide view by using five samples per point on the time axis. One way that works well in general is to scan five samples for min and max. You could then draw a vertical line at that time-axis point to represent the range of values. That way, the waveform would look more regular.

As the waveform sampling rate increases, the closer you are to getting all the points in the analog version of the waveform. The more horizontal resolution you have in you graphing view you have less you'll end up with longer vertical range lines—the most ideal being one for one, of course, in which case they are always points.

  • $\begingroup$ If the waveform is more complex, you can generate it at a sufficiently high sample rate that's my main problem. Usually, I exactly do this kind of min/max approch. But when the signal is already sampled (i.e. wav file). Here, I need to synthesize the signal.If I know my max hz would be 22khz, I need to render it calculating "sin" 44100 times; than search local min/max for every 44100/plotWidth sample. But the rendering become a huge task for a simple plot activity :( $\endgroup$
    – markzzz
    Commented Oct 23, 2020 at 6:40
  • $\begingroup$ OK, I see you're literally showing a full second in your example above, that makes sense. I didn't catch your code link the first time though. First, I think you don't need 44100 samples, just some multiple of the number of points you have. So, for instance, 4 x 480 (or 8 x 480, etc.) points to represent a second of sound, if it's one you're calculating. Or, if it's pre-recorded at 44.1k, you could skip samples. Instead of getting min and max of 92 samples per point, do it with every, 8 samples. you usually don't need to worry much about aliasing, the eye isn't as sensitive to it as the ear. $\endgroup$ Commented Oct 23, 2020 at 7:31
  • $\begingroup$ Tried your suggestions (8 x 480), but I don't get very good result (here frequency 50hz, 8x): jsfiddle.net/ebgk3957 . The more I increment freq, the worse its :( $\endgroup$
    – markzzz
    Commented Oct 23, 2020 at 7:58
  • $\begingroup$ I see...maybe try kvraudio, DSP and Plugin Development forum. There you'll probably find people who've tackled this problem for plugin displays. $\endgroup$ Commented Oct 23, 2020 at 21:26
  • $\begingroup$ A couple of comments...First, the 50 cycle display doesn't seem too bad, and most other frequencies look much better. Second...wish I had more time to check this out, but the display looks much different on my "retina" (XDR) display than on regular HD. And there's some antialiasing already, apparently, in the line drawing (non-integer points). Also, looking at something in between, like 30 Hz, is vastly improved on the second version. Not only even tops, but it looks like a sine wave, rounded, whereas the first code version looks like a triangle wave, pointy. $\endgroup$ Commented Oct 23, 2020 at 21:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.