Why is my JFreeChart rendering improperly? - java

I am trying to build a simple JFreeChart XYLineChart object, and embed it into a ChartPanel object.
For some unknown reason, the plot area doesn't look properly: You can see how gridlines are inconsistent in thickness, and the edges of the plot have these thick black markings in random places. What could be the cause of this?
public class Main extends JFrame() {
public static void main (String [] args) {
ECGPanel myECGPanel = new ECGPanel();
this.add(myECGPanel);
}
}
public class ECGPanel extends Jpanel {
lineChart= ChartFactory.createXYLineChart("ECG", "Time(ms)", "Voltage(mV)", dataset,
PlotOrientation.VERTICAL, true, false, false);
chartPanel=new ChartPanel(lineChart);
chartPanel.setPreferredSize(new Dimension(1000,400));
this.add(chartPanel);
}

As it was pointed out in comments, the problem relates to Windows and its Display settings. I have found the discussion about how Swing behaves on higher DPI systems here
Interestingly, I don't have this problem when I create a JFreeChart in JavaFX (both using a SwingNode and when using a ChartViewer). You can also see read about that here

Related

Number/Axis: how to force an immediate update of internal state during layout?

Triggered by a question about Slider and a slight bug, I tried to implement a SliderSkin that makes use of axis services, in particular its conversion methods between pixel and value. Works fine except that NumberAxis keeps its conversion offset and scale factor as internal fields that are updated only during a layout pass.
Which poses a problem, if I want to use the conversion during a layout pulse for updating another collaborator: in the case of a Slider that would be the thumb.
Below is a small examples to demonstrate the problem: simply a NumberAxis and a CheckBox at some value. On startup, the box is placed at the value at the middle. For maximal effect, maximize the window and note that the box position is not changed - now sitting near the beginning of the axis. Actually, it's the same when resizing the window but not so visible - see the printout of the difference.
Options to make it work
delay the thumb positioning until the next layout pulse (feels clumsy)
force the axis to update immediately
Looking for a way for the latter (couldn't find anything except reflectively invoke the axis' layoutChildren).
The example:
public class AxisInvalidate extends Application {
public static class AxisInRegion extends Region {
NumberAxis axis;
Control thumb;
IntegerProperty value = new SimpleIntegerProperty(50);
private double thumbWidth;
private double thumbHeight;
public AxisInRegion() {
axis = new NumberAxis(0, 100, 25);
thumb = new CheckBox();
getChildren().addAll(axis, thumb);
}
#Override
protected void layoutChildren() {
thumbWidth = snapSize(thumb.prefWidth(-1));
thumbHeight = snapSize(thumb.prefHeight(-1));
thumb.resize(thumbWidth, thumbHeight);
double axisHeight = axis.prefHeight(-1);
axis.resizeRelocate(0, getHeight() /4, getWidth(), axisHeight);
// this marks the layout as dirty but doesn't immediately update internals
// doesn't make a difference, shouldn't be needed anyway
//axis.requestAxisLayout();
double pixelOnAxis = axis.getDisplayPosition(value.getValue());
Platform.runLater(() -> {
LOG.info("diff " + (pixelOnAxis - axis.getDisplayPosition(value.getValue())));
});
// moving this line into the runlater "solves" the problem
thumb.relocate(pixelOnAxis, getHeight() /4);
}
}
private Parent getContent() {
AxisInRegion region = new AxisInRegion();
BorderPane content = new BorderPane(region);
return content;
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(getContent(), 500, 200));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
#SuppressWarnings("unused")
private static final Logger LOG = Logger.getLogger(AxisInvalidate.class
.getName());
}
Actually, I think it's a bug: the value/pixel conversion is a public service of the Axis - that should work always.
Not sure if it helps for your initial issue but simply do the calculation manually. Another plus - request layout becomes needless and can be removed.
double range = axis.getUpperBound()-axis.getLowerBound();
double pixelOnAxis = axis.getWidth()*(value.get()-axis.getLowerBound())/range;
Just got a working hack from the bug report: we need to call axis.layout() after changing size/location and before querying the conversion methods, something like:
axis.resizeRelocate(0, getHeight() /4, getWidth(), axisHeight);
// doesn't make a difference, shouldn't be needed anyway
//axis.requestAxisLayout();
// working hack from bug report:
axis.layout();
double pixelOnAxis = axis.getDisplayPosition(value.getValue());
thumb.relocate(pixelOnAxis, getHeight() /4);

Embed processing 3 into swing

I'm trying to integrate Processing 3 into a swing application, but because PApplet doesn't extend Applet anymore I can't just add it as a component right away.
Is there anyway of embeding a Processing 3 sketch into Swing, it would be enough if I could just open the sketch in a seperate window without the PDE.
You can run a sketch from Java by extending PApplet and then using the runSketch() function to run that PApplet. It'll look something like this:
String[] args = {"MyPapplet "};
MyPapplet mp = new MyPapplet ();
PApplet.runSketch(args, mp);
public class MyPapplet extends PApplet {
public void settings() {
size(200, 100);
}
public void draw() {
background(255);
fill(0);
ellipse(100, 50, 10, 10);
}
}
Then if you want to get at the underlying component, you have to write code that depends on which renderer you're using. Here's how you'd do it with the standard renderer:
PSurfaceAWT awtSurface = (PSurfaceAWT)mp.surface;
PSurfaceAWT.SmoothCanvas smoothCanvas = (PSurfaceAWT.SmoothCanvas)awtSurface.getNative();
Once you have the SmoothCanvas, you can remove it from its frame and add it to yours.

Create a video using processing opengl

I am creating a REST API to generate video dynamically based on user input and provided animation types. So, I am using processing 2.2.1 for this.
I want to generate 3D animation using OPENGL. But OPENGL requires Window object. Since I am using processing in background to just generate frame, how can I use processing with OPENGL to generate animated frames without interactive means without displaying the window.
My sample code
import com.hamoid.VideoExport;
import processing.core.*;
public class CircleSketch extends PApplet {
private VideoExport videoExport;
public void setup() {
size(400, 400,OPENGL);
videoExport = new VideoExport(this, "F:/work/tmp.mp4");
background(0);
}
public void draw() {
background(0);
fill(200);
rotateX(radians(50));
rectMode(CENTER);
rect(width/2,height/2, 100, 100);
videoExport.saveFrame();
}
}
DisplayFrame Class
public class DisplayFrame extends javax.swing.JFrame {
public DisplayFrame(){
this.setSize(600, 600); //The window Dimensions
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.JPanel panel = new javax.swing.JPanel();
panel.setBounds(20, 20, 600, 600);
processing.core.PApplet sketch = new CircleSketch();
panel.add(sketch);
this.add(panel);
this.setVisible(false);
//this is the function used to start the execution of the sketch
sketch.init();
}
public static void main(String[] args) {
new DisplayFrame().setVisible(false);
}
}
Any suggestion please???
how can I use processing with OPENGL to generate animated frames without interactive means without displaying the window.
In short terms: Given the current OpenGL driver models you can't (as long as you want to use a GPU for rendering). Period, that's how it is.
If you can live with software rendering (slow), then there's OSMesa. Also in the forseeable future there should be changes in the driver models, which allow to use OpenGL in a headless environment. Until then, you need a window of some sort on a graphics environment that actually actively feeds a display output (so it doesn't suffice to start a X11 server and background it).

how to dock javaplot window to a JPanel in java

I am using Javaplot for plotting graph.
import com.panayotis.gnuplot.JavaPlot;
public class test {
public static void main(String[] args) {
JavaPlot p = new JavaPlot();
p.addPlot("sin(x)");
p.plot();
}
}
The above code plots sin(x) on a dedicated window. I have a custom application window in my java swing project. How do I dock the java plot output graph inside a JPanel in my application window?
I haven't tried it, but it looks like you can wrap your JavaPlot in a JPlot, a subclass of JPanel, and add the panel to your custom application window:
customApplicationWindow.add(new JPlot(p));
For reference, interposing a call to JPlot#plot() worked:
JPlot jplot = new JPlot(p);
jplot.plot();
customApplicationWindow.add(jplot);

restoring manual domain axis range after zooming out in jfreechart

I'm using JFreeChart to create a timeseries chart in my application.
I'm setting it's domain axis range manually using:
...
plot.getDomainAxis().setAutoRange(false);
Calendar c1=Calendar.getInstance();
c1.set(Calendar.HOUR_OF_DAY, 10);
c1.set(Calendar.MINUTE, 0);
Calendar c2=Calendar.getInstance();
c2.set(Calendar.HOUR_OF_DAY, 18);
c2.set(Calendar.MINUTE, 0);
plot.getDomainAxis().setRange(c1.getTimeInMillis(),c2.getTimeInMillis());
...
Zooming in to chart and then zooming out (Using mouse on chartplot itself) triggers AutoRange on both axis that makes Domain axis range change to series borders and not my own manual rages.
Example (Look at Domain axis's range):
Before zooming in-out (Correct):
After zooming in-out (Incorrect-is Auto ranged):
How can I make it to zoom out to my manually set range?
Thanks
You might try restoreAutoBounds(), shown here, followed by your custom domain setting.
Addendum: The behavior you see is defined in the mouse listener implementation of ChartPanel. You could override chartProgress() and restore your domain axis when the chart is finished drawing and not zoomed.
here a solution:
class MyNumberAxis extends org.jfree.chart.axis.NumberAxis
{
private boolean m_RestoreDefaultAutoRange;
MyNumberAxis()
{
super();
}
MyNumberAxis(String label)
{
super(label);
}
MyNumberAxis(String label, boolean restoreDefaulAutoRange)
{
super(label);
m_RestoreDefaultAutoRange = restoreDefaulAutoRange;
}
#Override
protected void autoAdjustRange()
{
if( m_RestoreDefaultAutoRange )
{
Plot plot = getPlot();
if( plot != null && plot instanceof ValueAxisPlot)
{
Range r = getDefaultAutoRange();
setRange(r, false, false);
}
}
else
super.autoAdjustRange();
}
}
Create an instance of MyNumberAxis setting the boolean to true and use it in your plot (plot.setRangeAxis() method). If you want to behave like the default NumberAxis, pass false as boolean.
Magallo's solution above worked great. I found it even more useful if I added another constructor:
MyNumberAxis(String label, boolean restoreDefaulAutoRange, Range defaultRange) {
super(label);
m_RestoreDefaultAutoRange = restoreDefaulAutoRange;
setDefaultAutoRange(defaultRange);
}
I created a custom NumberAxis with a fixed range. Zooming out will auto-zoom to this fixed range.
class FixedRangeNumberAxis extends NumberAxis
{
private Range range;
FixedRangeNumberAxis(String label, Range range)
{
super(label);
this.range = range;
}
#Override
protected void autoAdjustRange()
{
setRange(range, false, false);
}
}

Categories