I've created a XYChart where X axis are names and Y axis are decimal numbers (floats)
The problem is, when I change chart lists from a table with a listener it works wonderful, but when I change it from a "forward" button, it doesnt.
forward button, only selects the next table item so in theory should work, since doing it manually works. But it doesnt.
Debugging the code I've realized that, when inserting values to the chart manually selecting the table row, the decimal inserted inside the XYChart object is: 3.692
but selecting from button results in something on the lines of: 3.6919999999004857554
I've tried:
Using float directly
Using double directly
Using BigDecimal directly
Setting bigDecimal's scale to 3 values and Half Up rounding mode
Producing float and double from BigDecimal
Using String.valueOf and then going back with Float.valueOf
Hardcoding a float value like 2.2f (Resulting in 2.200000000000000324234)
All of them produces a "correct" decimal stored in a variable (decimalNumber in the code), but when inserted into the chart, they show the wrong value, which ultimately is causing my UI to crash.
This is the line inserting decimals
dataSerie.getData().add(new XYChart.Data(hour, decimalNumber));
Here you can see how adding new Series goes as expected
Here you can clearly see how adding new serires DOESNT go as expected
As you can see, 2.2f is inserted as 2.200000047683716
method adding the value to the chart
private void addDataToSerie(XYChart.Series dataSerie, String hora, float consumo) {
dataSerie.getData().add(new XYChart.Data(hora, 2.2f));
}
Related
I'm working on an old script and I've hit a problem for a configuration that does not appear to be documented. I have a dynamically created bar chart. The bars are vertical. Everything is fine except the position of the bars on the X axis. The first and last one are half cut off. I can fix it easily after producing the spreadsheet. I click on the X-axis and switch the position to "Between tick marks" instead of "On tick marks." I cannot find anything in any form of PHPExcel documentation for setting the position of the X axis to "between" instead of "on." Does this setting exist?
PHPExcel has been replaced by PHPSpreadsheet, but there are cases where it is not possible to change from PHPExcel to PHPSpreadsheet.
The option that must be set is "crossBetween" for the X Axis. PHPExcel does not make this a customizable option. It is hard-coded in Charts.php with the value "midCat". That setting places the first bar directly under the Y axis and the last bar hanging off the right side of the chart. Each bar is cut off. To place the bars between the ticks, edit Charts.php and change the entry for "midCat" to "between". You should only find "midCat" once in the file. This will hard-code all charts to be between the ticks. Change it back if you want it back to what it used to be.
The proper fix is to make this an option you can change. That requires editing multiple files. The Axis object needs a cross_between option. Then, a setter is needed to update that option. The writer needs to pull from that option instead of hard-coding the value. Chart lets you get the X Axis, but you can't set it once you update an option. So, you need a setter for the X Axis for the chart. Then, you can create a chart, get the X Axis, change the crossBetween value, and set the updated axis in the chart.
UPDATE 25-09-2018
In a bid to create a simpler demo (posted here: http://jsfiddle.net/bLgj4vc7/3/) for this question, I finally discovered the root cause of the problem. I have also managed to work around it, which I have posted as an answer.
I am using standalone bokehjs in my webapp. My problem is that the renderer is not updating its line glyph with updated datasource (or at least this is what the problem looks like to me).
This jsfiddle: http://jsfiddle.net/uwnqcotg/8/ demonstrates the problem. Please ignore any bad coding conventions in it; its a quick, one-off demo.
In the fiddle, the plot is loaded with a dataseries which is rendered fine and dandy. The plot can be updated in two ways:
Update Plot Once By Overwriting CDS.data Object overwrites the ColumnDataSource.data object at one-go, thus adhering to the bokeh principle of maintaining same column lengths.
Start Stream With CDS.stream employs the ColumnDataSource.stream() and updates the plot at a regular interval with randomly generated, but incremental dataseries.
In the first approach, it looks like the glyph is being updated - the axes sure are updated in accordance with the dataseries printed in the console for reference. But, the plotted glyph and the dataseries show a mismatch. To me, it looks like the glyph plotted when the plot initialized simply re-adjusted to the new axes, though I cannot be sure.
In the second approach, again, the axes are updated, but the glyph isn't. Again, the originally plotted glyph seem to re-adjust to the new axes ranges. Moreover, the rollover attr seems to be ignored as the renderer simply keeps accumulating data.
Overall, my observation is that any data provided to the renderer during its initialization is plotted correctly, but any subsequent streamed update or even an overwrite are not. Though I may be wrong here.
On the other hand, between me and bokeh, I am inclined to believe I am doing something wrong or am missing something. So what is it?
As updated in the question, in a bid to create a simpler demo posted here http://jsfiddle.net/bLgj4vc7/3/, I ran across the root cause of this problem:
It looks like bokehjs has a bug where a renderer, once initialized with a certain length of dataset, sticks to that length even for subsequent updates in dataset. In other words,
If a renderer was initialized with an empty dataset {x:[], y:[]}, even if the renderer.data_source is updated with a populated dataset later on, the renderer sticks to the zero length and nothing is drawn on the plot.
For an initial dataset of length 5, only first 5 points will be read from any subsequent updates and the glyph will be updated accordinly. Rest of the points are not acknowledged.
I don't know whether the problem is whether renderer doesn't read beyond the initial length or whether it does but fails to redraw the glyph on the plot. The ColumnDataSource sure is updated correctly.
The fiddle linked in this answer best demonstrates the problem.
So what is the solution? At the moment, this workaround: initialize the renderer with a dataset filled with NaNs, which has a length equal or more than the maximum number of datapoints you want to plot for a single dataseries.
So, if in a line glyph, I wish to plot maximum 100 datapoints, then:
const plot = Bokeh.Plotting.figure()
const maxDataPoints = 100 // maximum number of points I want for this glyph
const emptyData = Array().fill().map(_ => NaN)
const cds = new Bokeh.ColumnDataSource({x: emptyData, y: emptyData})
const renderer = plot.line({field: 'x'}, {field: 'y'}, {source: cds, line_width: 2})
// now any subsequent updates to datasource of renderer will update its glyph on the plot.
renderer.data_source.data = {
x: dataLengthLessOrEqualToMaxDataPoints.x,
y: dataLengthLessOrEqualToMaxDataPoints.y
}
Of course, I think this behaviour of bokehjs is either a bug or I am missing an undocumented step in initialization. Either way, its worth creating an issue on github: https://github.com/bokeh/bokeh/issues/8277
In one of our pages I've created a detail screen with some information divided in blocks. I've used HorizontalLayouts with setExpandRatio for this. Here is how this is divided (all values made black for privacy reasons):
The final Label of the second row (now containing ---) should actually be empty instead. All the blocks are basically Vaadin Labels, with values in it. However, these values can sometimes be null, in which case I don't want to show anything in the Label.
When I use an empty String however instead of ---, it will look like this:
As you can see at the final Label of the second row, it is now missing it's border (and possible other styles we might add in the future), because Vaadin automatically put the expandRatio of Labels with an empty input to 0, turning the width to 0px.
I know you can set the actual width of a Label as filler, but in this case it's simply a question whether the value that's supposed to be in that Label is or isn't null.
I've also tried a space as value, but it just ignores it and behaves the same as the empty value. And when I " " as value (without setting the Label to HTML-mode), it outputs this literally as on the screen.
Is there any value I could use for the Label when the value is null to still show the style with borders, but without value?
EDIT: Hmm, when I use and set the ContentMode of the Label to HTML it seems to work. Is this the intended work-around for this issue (which means I'll have to set ContentMode to HTML for all Labels with the potential of containing an empty value), or is there another workaround by changing this 'empty' value alone?
Ok, I ended up using my solution provided in the EDIT. For all these Labels I had already created a BorderedLabel class, so I simply added setContentMode(ContentMode.HTML); to it, and used when the value is null in our util helper class.
Here is my Problem:
I'm currently using a ColumnChart to display 6 label/value pairs.
When two labels are the same, the chart stacks them up, one on top of the other.
I want to display these duplicates side by side, their value might be the same or it might be distinct.
My first thought was to append a unique id to the label, but that's not possible according to the client. So, is there a way to tell the chart to also take a hidden id into consideration?
Someone suggested to do some sort of grouping, but I need to display each chart separate, as if they were distinct charts.
the chart's data provider is an array of these objects:
obj.description = "des";
obj.countV = 3;//some arbitrary number
obj.id = 2; //a unique id...
the chart code:
I found my solution:
append an index # at the end of each column label.
Use a labelFunction to remove the last char:
columnLabel.slice(0, -1);
that fooled the chart into thinking they're all uniques but display all duplicates side by side.
Using Zedgraph (asp.net). I have a bar graph based on datetime x points. The first bar does not have a label. The first label is at the y-axis corresponding to a day before my first day point. I am not too concerned about this. However the second label is at the second bar. I need the first bar to have a label. I do have MyPane.XAxis.Scale.IsSkipFirstLabel = false.
How do I force the first bar to have a label? Why is ZedGraph not putting a label there?
Addition:
I want '5/20' to display for the first bar instead of 5/19 under the y-axis. I don't even have an entry for 5/19.
alt text http://i50.tinypic.com/29ogx0n_th.gif
OK, I don't know if that's exactly what you need, but:
First, adjust your scale ranges manually:
zg1.MasterPane[0].XAxis.Scale.Min = (double)new XDate(2010, 05, 19);
zg1.MasterPane[0].XAxis.Scale.Max = (double)new XDate(2010, 05,30);
This will set the ranges of your scale to show one day before and one day after your data (this is needed to have extra space)
then, set the step:
zg1.MasterPane[0].XAxis.Scale.MajorStep = 1;
zg1.MasterPane[0].XAxis.Scale.FontSpec.Angle = 90f;
This will cause you will have one label for each day. In fact, this is the only way to have more or less control over the labels that appear. I've also changed the angle of labels (in normal position it would overlap).
But it would create the labels for first and last extra days too (margins). So we need to disable these two entries (now it would work, because you've set the ranges manually).
zg1.MasterPane[0].XAxis.Scale.IsSkipFirstLabel = true;
zg1.MasterPane[0].XAxis.Scale.IsSkipLastLabel = true;
If you just want to disable this first and last extra label and leave the rest to the ZedGraph, just ommit the second step. But the outcome could be sometimes unpredictable.