- Notifications
You must be signed in to change notification settings - Fork6
OpenGL based 2D Plotting Library for Java using AWT and LWJGL
License
hageldave/JPlotter
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
OpenGL based 2D Plotting Library for Java using AWT/Swing andLWJGL throughlwjgl3-awt.An AWTGraphics2D fallback solution was introduced to support systems lacking OpenGL-3.3 as well as MacOS.
JPlotter's concept is pretty straight forward, you get aJPlotterCanvas
that is backed by OpenGL (or not in case of fallback).What is displayed by this canvas depends on the setRenderer
.Most likely you want to set aCoordSysRenderer
that displays a coordinate system.Within that coordinate system you may want to display points or lines, which you can do by again using aRenderer
(or multiple) as content.APointsRenderer
can be used to draw points as in a scatter plot, or aLinesRenderer
can be used to make a line chart or contour plot.
JPlotter is also capable of exporting plots as Scalable Vector Graphics (SVG) throughApache Batikas well as exporting to portable document format (PDF) throughApache PDFBox.
More details and information can be found in theWiki.
JPlotter is available as Maven artifact at the Central Maven Repository.
<dependency> <groupId>com.github.hageldave.jplotter</groupId> <artifactId>jplotter</artifactId> <version>1.0.4</version></dependency>
See theGallery for more images.
Before visualizing anything, some data has to be generated first.Lets sample the sine function so we can later plot a line.
DoubleUnaryOperatorfx =Math::sin;intnumCurveSamples =100;double[]curveX =newdouble[numCurveSamples];double[]curveY =newdouble[numCurveSamples];for(inti=0;i<numCurveSamples;i++){doublex =i*Math.PI*2/numCurveSamples;doubley =fx.applyAsDouble(x);curveX[i]=x;curveY[i]=y;}
Lets also mix in some random samples for plotting points.
intnumPointSamples =400;double[]pointsX =newdouble[numPointSamples];double[]pointsY =newdouble[numPointSamples];double[]diffToCurve =newdouble[numPointSamples];for(inti=0;i<numPointSamples;i++){doublex =Math.random()*Math.PI*2;doubley =Math.random()*Math.PI*2-Math.PI;diffToCurve[i] =y-fx.applyAsDouble(x);pointsX[i]=x;pointsY[i]=y;}
Now that data is set up, we are good to go and can think about representation of the data.The sine samples should be visualized as a line, whereas the random samples should be displayed as points.Lets also divide the points into 3 classes:
- y(x) < sin(x)-0.5
- sin(x)-0.5 <= y(x) <= sin(x)+0.5
- sin(x)+0.5 < y(x)
LinessineLine =newLines();intsineColor =0xff66c2a5;sineLine.setGlobalThicknessMultiplier(2) .setStrokePattern(0xf790) .addLineStrip(curveX,curveY) .forEach(segment ->segment.setColor(sineColor));PointspointsC1 =newPoints(DefaultGlyph.CROSS);PointspointsC2 =newPoints(DefaultGlyph.CIRCLE);PointspointsC3 =newPoints(DefaultGlyph.CROSS);intc1Color =0xff8da0cb,c2Color =sineColor,c3Color =0xfffc8d62;for(inti=0;i<numPointSamples;i++){if(diffToCurve[i] < -0.5){pointsC1.addPoint(pointsX[i],pointsY[i]).setColor(c1Color); }elseif(diffToCurve[i] >0.5) {pointsC3.addPoint(pointsX[i],pointsY[i]).setColor(c3Color); }else {pointsC2.addPoint(pointsX[i],pointsY[i]).setColor(c2Color); }}
Alright next we put everything into a coordinate system.
CoordSysRenderercoordsys =newCoordSysRenderer();CompleteRenderercontent =newCompleteRenderer();coordsys.setContent(content .addItemToRender(sineLine) .addItemToRender(pointsC1) .addItemToRender(pointsC2) .addItemToRender(pointsC3));// lets set the coordinate view to cover the whole sampling spacecoordsys.setCoordinateView(-.5, -3.3,6.5,3.3);
We can also add a legend to the plot so that a viewer can make more sense of the viz.
Legendlegend =newLegend();coordsys.setLegendRightWidth(80);coordsys.setLegendRight(legend .addLineLabel(2,sineColor,"f(x)") .addGlyphLabel(DefaultGlyph.CROSS,c1Color,"< f(x)-0.5") .addGlyphLabel(DefaultGlyph.CIRCLE,c2Color,"~ f(x)") .addGlyphLabel(DefaultGlyph.CROSS,c3Color,"> f(x)+0.5"));
We will use a blank canvas to display our coordinate system.For exploring the plot we can add some controls for zooming.
booleanuseOpenGL =true;JPlotterCanvascanvas =useOpenGL ?newBlankCanvas() :newBlankCanvasFallback();canvas.setRenderer(coordsys);// lets add some controls for exploring the datanewCoordSysScrollZoom(canvas,coordsys).setZoomFactor(1.7).register();newCoordSysViewSelector(canvas,coordsys) { {extModifierMask=0;/* no need for shift to be pressed */}publicvoidareaSelected(doubleminX,doubleminY,doublemaxX,doublemaxY) {coordsys.setCoordinateView(minX,minY,maxX,maxY); }}.register();
Nice, now we conclude with some typical AWT/Swing code to launch the viz in a JFrame.
JFrameframe =newJFrame("Example Viz");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.getContentPane().add(canvas.asComponent());canvas.asComponent().setPreferredSize(newDimension(480,400));canvas.asComponent().setBackground(Color.white);// register a listener that will cleanup GL resources on window closingcanvas.addCleanupOnWindowClosingListener(frame);SwingUtilities.invokeLater(()->{frame.pack();frame.setVisible(true);});
We can also add a pop up menu for exporting to SVG, PDF or PNG.
PopupMenumenu =newPopupMenu();canvas.asComponent().add(menu);canvas.asComponent().addMouseListener(newMouseAdapter() {publicvoidmouseClicked(MouseEvente) {if(SwingUtilities.isRightMouseButton(e))menu.show(canvas.asComponent(),e.getX(),e.getY()); }});// Exporting SVGMenuItemsvgExport =newMenuItem("SVG export");svgExport.addActionListener(e->{Documentsvg =SVGUtils.containerToSVG(frame.getContentPane());SVGUtils.documentToXMLFile(svg,newFile("example_export.svg"));System.out.println("exported SVG.");});menu.add(svgExport);// Exporting PDFMenuItempdfExport =newMenuItem("PDF export");pdfExport.addActionListener(e->{PDDocumentdoc =PDFUtils.containerToPDF(frame.getContentPane());doc.save("example_export.pdf");doc.close();});menu.add(pdfExport);// Exporting PNGMenuItempngExport =newMenuItem("PNG export");pngExport.addActionListener(e->{Imgimg =newImg(frame.getContentPane().getSize());img.paint(g ->frame.getContentPane().paintAll(g));ImageSaver.saveImage(img.getRemoteBufferedImage(),"example_export.png");System.out.println("exported PNG.");});menu.add(pngExport);
About
OpenGL based 2D Plotting Library for Java using AWT and LWJGL