How can I make the Y axis in a Unovis chart start at 0? - visualization

The Y axis seems to be dynamic and depends on the data.
Code:
import { VisAxis, VisLine, VisXYContainer } from '#unovis/react'
import { data } from './data'
export default function() {
return (
<VisXYContainer data={data}>
<VisLine x={d => d.x} y={d => d.y}/>
<VisAxis type='x'/>
<VisAxis type='y'/>
</VisXYContainer>
)
Looks like: result
Is there a way to make it start at 0?

Yes, you can set the Y axis range (or the Y scale domain in D3 terms) for all XY components (Line, Area, Scatter, etc ...) by setting the yDomain property of XYContainer.
Here's an example in React:
<VisXYContainer yDomain={[0, undefined]} ...>
<VisLine ... >
</VisXYContainer>
The yDomain value of [0, undefined] means that the lower limit will be 0 and the upper limit will be determined automatically based on the data.
You can read more about controlling the chart's scales in the documentation: https://unovis.dev/docs/xy-charts/Container#ydomain

Related

X axis glitch Fl_charts

I have data in the form of [DateTime, num]. I have converted the DateTime object into a string and used it as a x-axis label. I am getting this glitch now. Is there a property which I need to change to fix this?
As you can see, there is a repetition of the x axis labels at either end. I am using Fl_Chart library. If you require my current code I can attach it.
fl_chart uses the interval you provide to determine which points should have labels for, however, it also creates a label for 0 and maxX. You can fix it by adding
if (value % (xAxisInterval?.ceil() ?? 1) == 0) {
//return label
}else{
return SideTitleWidget(
axisSide: meta.axisSide,
child: Container(),
);
}
to your getTitlesWidget function. Where xAxisInterval is the value you passed into your SideTitles object for interval for the xAxis.

Google charts, is it possible to have 2 different vertical axis values?

For better understanding of this question, let me show a working example in TradingView webpage, on which the following chart shows the combination of Momentum (area chart) + ADX (line chart):
As you can see, there are 2 vertical values, at left side is the ADX which the scale goes usually from 0 to 60(+-), but the right side, it can grow much more.
On my attempt to achieve the same here, the momentum (area chart) has a huge range, and the adx (lineal chart) goes from 0 to 60, so when it tries to fit both values under the same scale, my blue line looks like it's almost zero, in comparison with the area chart values. (Mouse-over the blue line showing that is currently 43)
So I think you get the point, would it be possible to have 2 scales/vAxis for each series of values?
I checked documentation already but nothing here seems to refer to what I mention:
https://developers.google.com/chart/interactive/docs/gallery/combochart
And just in case you need the options provided to the chart, nothing advanced, just the basic examples:
options:{
seriesType: 'area',
series: {
0: { type: 'line', color: 'blue' }
}
};
use option --> targetAxisIndex -- in the series option...
zero is the default v-axis
targetAxisIndex: 0
to create a second v-axis, assign one of the series to index 1
series: {
1: {
targetAxisIndex: 1
}
}
Found the solution over this post in the documentation, it is conceptually known as DUAL-Y Charts
https://developers.google.com/chart/interactive/docs/gallery/columnchart#dual-y-charts

Google Charts offsetting the horizontal axis marker labels

Does anyone know if its possible to offset the markers so they appear between the column of a google chart?
So that it appears like this design mockup...
Instead of the markers being directly inline with the columns like below which is the default behaviour of the google.visualization.ColumnChart api.
I have search through the documention, however cannot find any references to options that would allow for this kind of customisation. Does anyone know if perhaps there is a way of manipulating the layout after it has been rendered? Or if in fact there is an option to do this but I've just overlooked it?
Thanks
The chart is rendered in a <svg> structure containing <g>, <rect>, <text> (and other) elements. The structure differs a lot form chart to chart, and the internal ordering can change if basic chart elements are left out. The horizontal axis elements is rendered as something like
<text text-anchor="middle" x="468.46875" y="343.05" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">12</text>
To get an idea of where to look for those <text> elements in the <svg> structure you can copy the rendered code of the chart to a editor capable of styling code, or use a online code beautifier.
Then simply iterate through the <svg> by using DOM methods such as querySelector, querySelectorAll, getElementsByTagName etc.
See this google.visualization.ColumnChart :
By changing the x attribute of each <text> element that belongs to the horizontal axis we can get the labels to appear between the columns :
google.visualization.events.addListener(chart, 'ready', updateAxis);
function updateAxis() {
var x,
svg = document.getElementById('chart').querySelector('svg'),
g = svg.querySelectorAll('g'),
chartArea = g[3].querySelectorAll('g'),
hAxisTexts = chartArea[5].querySelectorAll('text');
//0-15 labels, the rest belongs to the yAxis
for (var i=0;i<16;i++) {
x = parseFloat(hAxisTexts[i].getAttribute('x'));
if (x>9) {
x = x-15;
} else {
x = x-18;
}
hAxisTexts[i].setAttribute('x', x);
}
}
demo -> http://jsfiddle.net/hrrL45oq/
This is only an example. You will perhaps need to target a different <g> element holding the <text>'s, and how you manipulate x or other attributes of <text> depends of the layout of the chart.

Line chart/graph with an irregular threshold field

Looking to create a bar chart with an irregular, colored threshold field in the background, so that each data point has its own individual set of min/max thresholds, which ultimately would look something like this: http://dcalvitti.webs.com/plant/SAMPLE.png
Looked at D3 examples like this one: http://bl.ocks.org/mbostock/4062844
Can the latter example be manipulated to look more like the image I created?
Thanks in advance..
The graph shown in your sample image is actually much easier than the linked example; for that, you don't need to create a clipping path and you don't need to draw the line twice with two different colours.
For drawing the coloured background, use an area-path generator, created with d3.svg.area(). Set the y0 accessor function to be extract your minimum value for each point in your data array, and the y1 accessor function to extract the maximum value.
Then draw the line overtop as a normal line graph with a d3.svg.line() path generator.
Working example, adapted from the fiddles in the comments: http://jsfiddle.net/h45CD/12/
(Note: I commented out half the dataset, since the "year" values were repeated, not sure what that was supposed to represent.)
Key code:
// Define the value line path generator
var line = d3.svg.line()
.x( function(d) { return x(d.year); } )
.y( function(d) { return y(d.temp); } );
// Define the area path generator
var area = d3.svg.area()
.x( function(d) { return x(d.year); } )
.y0( function(d) { return y(d.min); } )
.y1( function(d) { return y(d.max); } );
/* ... */
// Add the background area showing the historic range
svg.append("path")
.datum(data)
.attr("class", "historicRange")
.attr("d", area);
// Add the value line
svg.append("path")
.datum(data)
.attr("class", "dataline")
.attr("d", line);
Edit based on comments
If you do want a line that changes colour depending on historic values, as opposed to a line drawn overtop of a background range, the most straight-forward solution is probably to create a <pattern> element consisting of the different coloured regions, and use this to stroke the value line.
You'll want to familiarize yourself with the different options for the pattern element. This MDN tutorial has a good intro, or you could dive into the full W3 specs.
For this situation, we want the pattern to be sized and positioned relative to the coordinate system used for drawing the line, regardless of the size or shape of the line itself. That means we will be setting both the patternUnits and the patternContentUnits to be userSpaceOnUse. The height and width of the pattern will be the height and width of the plotting area.
Within the pattern we will draw the area that represents the max-min range, but we also need to draw separate areas, with different colours, for values above the max and values below the min. We can use the same area generator for each, but need to change the y0/y1 accessor functions each time.
Key code:
// Add the pattern showing the historic range
var pattern = defs.append("pattern")
.datum(data) //add the data to the <pattern> element
//so it will be inherited by each <path> we append
.attr({
"patternUnits":"userSpaceOnUse",
"patternContentUnits":"userSpaceOnUse",
"width": width,
"height": height
})
.attr("id", "strokePattern");
pattern.append("path")
.attr("class", "historicRange between")
.attr("d", area);
pattern.append("path")
.attr("class", "historicRange above")
.attr("d", area.y1( 0 )
.y0( function(d){return y(d.max);} )
);
pattern.append("path")
.attr("class", "historicRange below")
.attr("d", area.y1( function(d){return y(d.min);} )
.y0( height )
);
// Add the value line
plot.append("path")
.datum(data)
.attr("class", "dataline")
.attr("d", line)
.style("stroke", "url(#strokePattern)");
Working example: http://jsfiddle.net/h45CD/14/
I'm including a web page link with charts authored by myself based on AMCharts and with the help of that web site's founder. Contains several examples of the above question and more..
http://dcalvitti.webs.com/SAMPLE/NEWWEBINDEX.html
The charts provided are still being worked on. For example, AMcharts does have a function that clips the color of a line above/below a certain value which I didn't know about, so there is still work to be done. I spent many weeks on the charts and thought I'd share. I'm sure someone will find something new here down the road...

World.QueryAABB giving incorrect results in libgdx

I'm trying to implement mouse selection for my game. When I QueryAABB it looks like it's treating objects much larger than they really are.
Here's what's going on in the image
The blue box is an actor containing a body that I'd like to select
The outline on the blue box is drawn by Box2DDebugRenderer
The mouse selects a region on the screen (white box), this is entirely graphical
The AABB is converted to meters and passed to QueryAABB
The callback was called for the blue box and turned it red
The green outline left behind is a separate body to check if my conversions were correct, this is not used for the actual selection process
It seems to be connected to my meter size, the larger it is, the more inaccurate the result is. At 1 meter = 1 pixel it works perfectly.
Meter conversions
val MetersToPixels = 160f
val PixelsToMeters = 1/MetersToPixels
def toMeters(n: Float) = n * PixelsToMeters
def toPixels(n: Float) = n * MetersToPixels
In the image I'm using MetersToPixels = 160f so the inaccuracy is more visible, but I really want MetersToPixels = 16f.
Relevant selection code
val x1 = selectPos.x
val y1 = selectPos.y
val x2 = getX
val y2 = getY + getHeight
val (l,r) =
if (x2 < x1)
(x2,x1)
else
(x1,x2)
val (b,t) =
if (y2 < y1)
(y2,y1)
else
(y1,y2)
world.QueryAABB(selectCallback, toMeters(l),toMeters(b), toMeters(r),toMeters(t))
This code is inside the act method of my CursorActor class. And selectPos represents the initial point where the use pressed down the left mouse button and getX and getY are Actor methods giving the current position. The next bit sorts them because they might be out of order. Then they are converted to meters because they are all in pixel units.
selectCallback: QueryCallback
override def reportFixture(fixture: Fixture): Boolean = {
fixture.getBody.getUserData match {
case selectable: Selectable =>
selected += selectable
true
case _ => true
}
}
Selectable is a trait that sets a boolean flag internally after the query which helps determines the color of the blue box. And selected is a mutable.HashSet[Selectable] defined inside of CursorActor.
Other things possibly worth noting
I'm new to libgdx and box2d.
The camera is scaled x2
My Box2DDebugRenderer uses the camera's combined matrix multiplied by MetersToPixels
From what I was able to gather, QueryAABB is naturally inaccurate for optimization. However, I've hit a roadblock with libgdx because it doesn't have any publicly visible function like b2testOverlap and from what I understand, there's no plan for there to be one any time soon.
I think my best solution would probably be to use jbox2d and pretend that libgdx's physics implementation doesn't exist.
Or as noone suggested I could add it to libgdx myself.
UPDATE
I decided to go with a simple solution of gathering the vertices from the fixture's shape and using com.badlogic.gdx.math.Intersector against the vertices of the selection. It works I guess. I may stop using QueryAABB all together if I decide to switch to using a sensor for the select box.