Because of the high rendering performance I am using uPlot to visualize historical sensor data.
Is there a way to add horizontal reference lines like recommended min/max values for a data series?
With other libraries that's often straight forward, like the ReferenceLine tag in recharts, but I haven't found anything yet with uPlot. Any hints?
Example: The orange dotted lines are the lower and upper acceptable bounds at 7.0 and 7.4. This image is rendered with recharts, but I want to migrate to uplot.
(There's a layer in front of the chart with the actual, min and max value which is totally independent of the chart.)
I found an acceptable aproach based on two examples in the uPlot repository:
https://leeoniya.github.io/uPlot/demos/trendlines.html
https://leeoniya.github.io/uPlot/demos/draw-hooks.html
The main idea is to handle one of the draw-hooks (draw, drawAxes, drawClear) and to directly drawing on the canvas.
Related
I'm working on replacing a dynamic chart implemented in highcharts. The current implementation is a line-area chart that expands over time with incoming streaming data, so the replacement needs to be dynamically alterable, and preferrably animated.
Currently I'm looking at D3 for the replacement. There are a few examples I've found which show that there may be something similar which is possible, such as the charts for streaming data found here, but in this example the line is redrawn at every iteration. It's not terribly inefficient as the visualization is limited to a fixed window of data, but in my case a high volume of data needs to be displayed from start to finish as the data streams in. Redrawing the chart at every addition will likely result in rapid performance loss.
In D3, is there a method of adding a single segment to an existing plot that does not require a redraw?
I ended up abandoning D3 as it required too much development to make it as presentable as an interactive chart that was ready out-of-the-box, but I did figure out how to do what I was thinking.
Instead of re-adding a new line with additional points at every iteration, I ended up using a path component which allows additional points to be added progressively. The path does have to be re-rendered and generates a short svg path string, so I'm not exactly sure which method is more efficient, but a short path string reduces complexity of the resulting html in the case that one were to add multiple lines to the plot, one for each segment.
If an addition to the path involves only the generation of a new string using concatenation of the original then I imagine this could be much more efficient than iterating through an array of series data that grows at every update.
The result was fast enough to keep up with streaming data without any visible slowing of the UI, but it was just unfortunate that I needed something a little more developed.
I'm trying to find a way to dynamically scale a chart's y-axis so the values are shown in single digits, with a exponential denotation at the top, effectively changing this:
To this:
Note, this works automatically in e.g. Matlab/Matplotlib/etc., but I'm struggling to find a solution with the web plotting frameworks (maybe my search language is wrong)... I know D3.js is not a charting library, but I'd be open to a solution that works with the frontend DC.js or the backend D3.js
Edit based on #Gordon's answer below, I get the following graph using this
chart.yAxis().tickFormat(d3.format('.1e'));
Is it somehow possible to move all of the e+6 to the top? Or do I need to write a custom scaling function and insert a separate text box myself?
In dc.js, the axes are straight from d3-axis.
Access them using chart.xAxis() and chart.yAxis(), and to reduce confusion, do this in a separate statement from the rest of your chart initialization.
You can use axis.tickFormat to control how the tick text is formatted.
You can use d3.format to do automatic formatting. It seems like exponent or SI notation might suit what you're doing, although it's not exactly the same as having the exponent in a separate text element like in your screenshot.
Putting it together, this is pretty close
chart.yAxis().tickFormat(d3.format('.1e'))
The tick formatting question comes up a lot. I wonder where we could put this information so that people don't have to ask.
I've been struggling the past few days to optimize performance on a D3 map, especially on mobile. I am using SVG transforms for zooming and panning but made the following observation: the overkill comes from path strokes used to fake spacing between countries.
I have uploaded a pair of sample maps for comparison:
http://www.nicksotiriadis.gr/d3/d3-map-1.html
http://www.nicksotiriadis.gr/d3/d3-map-2.html
The only difference between the two maps is the stroke path along the country paths, and the difference in performance is even noticeable on desktop devices - but more obvious on mobile. Removing the path strokes makes mobile performance a breeze..
I tried all kinds of svg stroke shape-rendering options without significant results.
Now to the question. Is there any way to remove a thin border from each country to fake the spacing between countries instead of using a stroke?
If anyone else has a different suggestion I'd love to hear it!
Update: Attaching explanation photo.
What I have drawn is this. The red arrow points to the country joints. When adding a stroke in a color same as the background to the country paths (here depicted in dark grey color) it creates the sense that the countries are seprated - however this adds a serious performance hit on mobile devices. What I am looking for is somehow re-shape the countries paths so that their borderlines are where the blue arrow points, but without having a stroke.
Update 2: People seem not to be able to understand what I am looking for, so I am updating this in order to make the question even clearer.
Let's assume that the original countries paths are shown on the left of this image. What I am looking for is a way that I can somehow 'contract' the paths inwards so that the newly created paths shown in red, leave enough empty space between them that will 'emulate' a stroke between them.
Doing this, will leave no use to having an extra layer of strokes, thus gain performance from only using paths instead of paths+strokes.
Update 2: Hello again, I seem to have found a half-solution to my problem. I managed to extract the topojson to shapefile, edit the shapefile the way I want (used a program named OpenJump), but the conversion takes away all the topojson properties I need - id, country name, so I can't convert back to the original topojson.
Does anyone have any suggestions?
D3 has a thing just for that: topojson.mesh() (see documentation). The idea is that since most countries share borders, there's no need to draw the shared borders twice. If you can draw each border only once, you get as much as 80% reduction in the number of strokes you have to draw. The mesh method does the javascript processing to turn a bunch of closed shapes (countries) into the multiline path of just the borders between them. You can then draw that multiline path into a single <path> object that you position on top of the fills.
The mesh looks like this.
Here's another example.
Finally found the answer. This radically improves d3 map performance!
1) I got my topojson file and extracted to shapefile using mapshaper.org. This gives 3 files: .shp, .shx, .dbf . From what I realized the .dbf file holds all the TopoJSON properties/attributes.
2) Opened the .shp shape file to OpenJUMP http://www.openjump.org/ - Which automatically imports the .dbf file as well.
3) I selected the countries layer and went to Tools > Analysis > Buffer.
4) Checked the Update geometry in source layer box so that the geometry is edited without losing the rest of the attributes/properties and added a negative Fixed Distance -0.1. This shrinked all the country geometries to the result I was looking for.
5) Saved Dataset as ESRI Shapefile
6) Reimported BOTH .shp and .dbf that were produced from OpenJUMP back to mapshaper.org - careful, BOTH files.
7) Exported as TopoJSON. Contains new shape and all original properties/attributes!
The following link has been updated with the new produced map; we have a 'bordered' look without the need of strokes.
http://v7.nicksotiriadis.gr/d3/d3-map-1.html
Compare the performance to this link that has the original shapes + stroke. Please try on mobile to see the performance difference!
http://v7.nicksotiriadis.gr/d3/d3-map-2.html
Also, here is the updated world map TopoJSON file in case someone wants some extra performance! :D
http://v7.nicksotiriadis.gr/d3/js/world-topo-bordered.json
There might be a couple of reasons of this behaviour (on my computer, everything is working fine at the same speed ):
Browser
Which browser do you use ? On Chrome, your exemples are working perfectly.
TopoJson
eg. previous answer.
Animation
You are launching the animation when the page is loading. You might want to add a delay (animation().delay(in ms)). There is also a function in D3: queue(), https://github.com/mbostock/queue which load the data before launching a function.
--
If none of this change your problem, and if you want it to work fine on mobile, you can try to mix D3 and Leaflet (map for mobiles), which is great in term of performance by loading tiles.
One example:
http://bl.ocks.org/zross/6a31f4ef9e778d94c204
Hope it helps
I have phasor information (polar vector data pairs, each with magnitude and angle, representing voltage and current measurements) that I would like to display using Javascript. They should look something like the image linked below (my rep isn't high enough to directly post it) which I stole from Jesse's question about MatPlotLib. I would also like to easily change which phasors are displayed by a simple mechanic like clicking on the legend entry.
See a phasor diagram example here.
While I have inspected several code sets, I have yet to find a chart package that is built to handle polar vectors like this. Is my Google-fu lacking or do I need to create everything from scratch?
I feel like this is a cheap workaround, but here's what I ended up doing:
I used the polar chart from jqWidgets and with the series type set to "column" and the flip property switched to "true." I put the data in an array with 0 entries for each possible angle except for where I wanted the phasor displayed. Each phasor gets a dedicated series so the legend lists them all. It's not perfect and the array is much larger than it really should need to be, but it's passable.
While it's not surprising that no power system display package is publicly available for Javascript, I'm sure one has to be out there for educational sites if nothing else.
Any ideas on where to even begin with making a violin chart using d3? Does it exist already?
I've looked around and have figured out how to do it using ggplot2 and was hoping there'd be a ready-made example that I could learn from but haven't found one yet.
I suppose I could do a really painful process of making various size bars on top of each other, or taking a distribution, rotating it and mirroring it. But surely there's a better way.
I needed that for myself so here it is: violin plot
As far as I know, nobody has done this before, but it shouldn't be too hard. I would start as if I was making a line chart (or boxed instead of lines) for one half of a violin. That is, create the appropriate x and y scales and add the data in. The result of this I would rotate and translate to the correct position. Then do the same thing again and mirror it as well to get the other half of the violin.
This may sound complex, but SVG has built-in support for these operations (rotating and mirroring). You should be able to approach this pretty much like drawing a line graph of the distribution with 2-3 simple operations on top of that. Wrap everything in a function and you've got something you can call to create a violin.
It of course also depends in what form you have the data to make the plot. A line plot might not be feasible because of too few data points, but then you can easily use bars instead.