DMelt:Plots/3 Custom Plots
Custom plots in 2D
You can create fully custom plots with arbitrary layouts by writing Jython and Java code and accessing internal methods. First, let us consider a simple plots based on the class jhplot.HPlotXY. Using the method "getPlot()" of this class one can return a plot object of the Plot class that can be changed using an arbitrary layout. Let us consider a simple example:
from java.awt import Color,Font from java.util import Random from jhplot import * c1 =HPlotXY("Functions",600,400) c1.visible() c1.setGTitle("Functions") c1.setNameX("X") c1.setNameY("Values") p1=F1D('x*x', -10,10) p1.setLineStyle(1) p2=F1D('x*x*cos(x)', -10,10) p2.setLineStyle(2) p2.setColor(Color.red) c1.setRangeY(0,3) c1.setRangeX(-1.2,1.2) c1.draw(p1) c1.draw(p2) # c1.export("test.svg");
The output plots is:
You can see that jhplot.HPlotXY is very similar to jhplot.HPlot. However, it has several features that can help to build non-standard layouts.
In order to access all such plotting zones, you can look at the following methods:
c1=HPlotXY("Cosmology",600,700,0) c1.visible() ef=c1.getFactory() plot=c1.getPlot() env=c1.Env()
The function "getFactory()" returns class, while getPlot() returns the actual plotting area. Look at the API of these classes:
The ElementFactory class cab be used to create axis, titles, legends and subplots. In order to export plots to one of the vector-graphics formats supported by dmelt, use the usual method:
c1.export("image.svg")
(change the extension to use different file format).
Now let us build an example that shows a plot with two subplots, custom title and data points with the legends.
from java.awt import *; from org.jplot2d.element import * from org.jplot2d.layout import * from org.jplot2d.sizing import * from org.jplot2d.transform import * from org.jplot2d.util import * from org.jplot2d.util import * from jhplot import * from array import * c1=HPlotXY("Cosmology",600,700,0) c1.visible() ef=c1.getFactory() p=c1.getPlot() title=ef.createTitle("Complex plot") title.setFontScale(2); p.addTitle(title); # subplots usp = ef.createSubplot() lsp = ef.createSubplot() usp.setPreferredContentSize(380, 260) lsp.setPreferredContentSize(380, 160); lsp.getMargin().setExtraTop(10); p.setLayoutDirector(GridLayoutDirector()); p.addSubplot(usp, GridConstraint(0, 1)); p.addSubplot(lsp, GridConstraint(0, 0)); #upper subplot Axes uspx = ef.createAxes(2) uspx[0].getTitle().setText("wavelength $\\mathrm{\\lambda}$ [$\\mathrm{\\micro}$m]"); uspx[0].getTitle().setFontSize(10); uspx[0].getTickManager().setRange(Range.Double(10, 2e6)); uspx[0].getTickManager().getAxisTransform().setTransform(TransformType.LOGARITHMIC); uspx[1].setLabelVisible(False); uspy = ef.createAxes(2); uspy[0].getTitle().setText("flux density [Jy]"); uspy[0].getTitle().setFontSize(12); uspy[0].getTickManager().setRange(Range.Double(0.05, 1200)); uspy[0].getTickManager().getAxisTransform().setTransform(TransformType.LOGARITHMIC); uspy[0].getTickManager().setLabelFormat("%.0f"); uspy[1].setLabelVisible(False); usp.addXAxes(uspx); usp.addYAxes(uspy); # lower subplot Axes lspx = ef.createAxes(2) lspx[0].getTitle().setText("wavelength $\\mathrm{\\lambda}$ [$\\mathrm{\\micro}$m]"); lspx[0].getTitle().setFontSize(10); lspx[0].getTickManager().setRange(Range.Double(10, 1500)); lspx[0].getTickManager().getAxisTransform().setTransform(TransformType.LOGARITHMIC); lspx[1].setLabelVisible(False); lspy = ef.createAxes(2); lspy[0].getTitle().setText("residual [Jy]"); lspy[0].getTitle().setFontSize(10); lspy[0].getTickManager().setRange(Range.Double(-0.7, 0.7)); lspy[0].getTickManager().setTicks(3); lspy[1].setLabelVisible(False); lsp.addXAxes(lspx); lsp.addYAxes(lspy); #Layer ulayer = ef.createLayer(); usp.addLayer(ulayer, uspx[0], uspy[0]); llayer = ef.createLayer(); lsp.addLayer(llayer, lspx[0], lspy[0]); #solid line solx = array('d', [10, 2000000]) soly = array('d', [0.09, 900]) sol = ef.createXYGraph(solx, soly); sol.setColor(Color.BLUE); sol.getLegendItem().setVisible(False); ulayer.addGraph(sol) #dashed line dlx= array('d',[10, 2000000] ) dly = array('d', [0.1, 820]) dl = ef.createXYGraph(dlx, dly); dl.setColor(Color.BLUE); dl.setLineStroke(ef.createStroke(1, [1, 3 ])); dl.getLegendItem().setVisible(False); ulayer.addGraph(dl); #ISO xx= array('d',[15] ) xy = array('d',[ 0.1059 ]); xye = array('d',[ 0.0212 ]); xl = ef.createXYGraph(xx, xy, None, None, xye, xye, "Xilouris et al. 2004"); xl.setColor(Color.GREEN); xl.setLineVisible(False); xl.setSymbolVisible(True); xl.setSymbolShape(SymbolShape.SQUARE); ulayer.addGraph(xl); # IRAS gx = array('d',[ 24.9, 59.9, 99.8 ]) gy = array('d',[0.187, 0.546, 0.559]) gye = array('d',[ 0.0281, 0.0819, 0.0839]) gl = ef.createXYGraph(gx, gy, None, None, gye, gye, "Golombek et al. 1988"); gl.setColor(Color.GREEN); gl.setLineVisible(False); gl.setSymbolVisible(True); gl.setSymbolShape(SymbolShape.FTRIANGLE); ulayer.addGraph(gl); # legend usp.getLegend().setPosition(None); usp.getLegend().setColumns(1); usp.getLegend().setLocation(-10, 250); usp.getLegend().setHAlign(HAlign.LEFT); usp.getLegend().setVAlign(VAlign.TOP); usp.getLegend().setBorderVisible(False); usp.getLegend().setFontSize(12); slrx =array('d',[ 10, 1000 ]); slry = array('d',[ 0, 0 ]); slrl = ef.createXYGraph(slrx, slry); slrl.setColor(Color.BLUE); slrl.getLegendItem().setVisible(False); llayer.addGraph(slrl); xry = array('d',[-0.01 ]); xrl = ef.createXYGraph(xx, xry, None, None, xye, xye); xrl.setColor(Color.GREEN); xrl.setLineVisible(False); xrl.setSymbolVisible(True); xrl.setSymbolShape(SymbolShape.SQUARE); xrl.getLegendItem().setVisible(False); llayer.addGraph(xrl); tx = array('d',[100, 160, 250, 350, 500]) tye = array('d',[0.129, 0.168, 0.215, 0.267, 0.375]) ty = array('d',[0.517, 0.673, 0.86, 1.074, 1.426]); tl = ef.createXYGraph(tx, ty, None, None, tye, tye, "This paper"); tl.setColor(Color.RED); tl.setLineVisible(False); tl.setSymbolVisible(True); tl.setSymbolShape(SymbolShape.FOCTAGON); ulayer.addGraph(tl) trry = array('d',[0.01, -0.03, -0.13, -0.21, -0.26]); tx = array('d',[100, 160, 250, 350, 500]) tye = array('d',[0.129, 0.168, 0.215, 0.267, 0.375]) trl = ef.createXYGraph(tx, trry, None, None, tye, tye); trl.setColor(Color.RED); trl.setLineVisible(False); trl.setSymbolVisible(True); trl.setSymbolShape(SymbolShape.FOCTAGON); trl.getLegendItem().setVisible(False); llayer.addGraph(trl);
The original package used to make this code is called "jplot2d" and the description of the most essential methods is give here jplot2d wiki.
The output image created by the above code is:
Building titles
After you create the "plot" object of the class org.jplot2d.element.Plot and "ef" factory object using org.jplot2d.element.ElementFactory class, you can add a title as:
from org.jplot2d.element import * title = ef.createTitle("Custom Title") title.setFontScale(2) plot.addTitle(title)
The "title" object belongs to org.jplot2d.element.Title class.
You can use TeX-like formatting of strings in plots. Entering math mode using a "dollar" symbol it is possible to insert Greek characters, for instance using
\\alpha - greek alpha \\beta - greek beta
{| class="wikitable sortable" border=1 ! # superscript symbol |- |} _ # subscript symbol
Here is how to show math:
text="$A_{1.3}^{b-3/2}$" text="$\\alpha_{1.3}^{\\beta-3/2}$"
The following special symbols are available:
- All the lower-case Greek letters.
- The following upper-case Greek letters: \Gamma, \Delta, \Theta, \Lambda, \Xi, \Pi, \Sigma, \Upsilon, \Phi, \Psi, \Omega .
- The \angstrom and \micro symbols.
To insert other symbols you can use the Unicode escape sequence \uxxxx , where xxxx is the hexadecimal code of the symbol. For example, \u2299 corresponds to the circle dot operator, which can also be used as symbol for the Sun. Use [1] table to look at how to map unicode characters.
Creating Axes
To create axised for X and Y, use "createAxis" method of "ef" factory object of org.jplot2d.element.ElementFactory class
xaxis = ef.createAxis(); yaxis = ef.createAxis(); # setting an axis transform to LOGARITHMIC xaxis.getTickManager().getAxisTransform().setTransform(TransformType.LOGARITHMIC);
The objects "xaxis" and "yaxis" belong to Axis class. To add an axis to the plot, use these methds:
plot.addXAxis(xaxis) plot.addYAxis(yaxis)
You may want 2 x-axes and 2 y-axes to box the plot contents. In this case, 2 x-axes or y-axes can be created and added together. The created 2 x-axes share the same tickManager. And so the 2 y-axes.
xaxes = ef.createAxes(2) yaxes = ef.createAxes(2) # setting an axis transform to LOGARITHMIC xaxes[0].getTickManager().getAxisTransform().setTransform(TransformType.LOGARITHMIC); plot.addXAxes(xaxes) # add them to the plot plot.addYAxes(yaxes)
Let us show how to make titles, subtitles and axes in this example:
from org.jplot2d.element import * from org.jplot2d.util import * from jhplot import * from array import * from java.awt import * c1=HPlotXY(False) c1.visible() ef=c1.getFactory() plot=c1.getPlot() title=ef.createTitle("Custom Title") title.setFontScale(2) plot.addTitle(title) subtitle = ef.createTitle("Custom Subtitle") subtitle.setFontScale(1.2) plot.addTitle(subtitle) copyRight = ef.createTitle('\u00A9 2012 jplot2d project (LGPL)'.decode('unicode-escape')) copyRight.setFontScale(1) copyRight.setColor(Color.BLUE.darker()); copyRight.setPosition(TitlePosition.BOTTOMRIGHT); plot.addTitle(copyRight); xaxis = ef.createAxis(); yaxis = ef.createAxis(); xaxis.getTitle().setText("x axis"); plot.addXAxis(xaxis); yaxis.getTitle().setText("y axis"); plot.addYAxis(yaxis);
The resulting plot is:
Creating layers
A layer can associate with a x-axis and a y-axis, i.e. it is associated with a x AxisTransform and a y AxisTrasform. When adding a layer to a plot, the associated x AxisTransform and y AxisTrasform must be given as arguments, and they must already exist in the plot (by adding the x axis and y axis object).
layer = ef.createLayer(); # The xaxis and yaxis must has been added to the plot plot.addLayer(layer, xaxis.getTickManager().getAxisTransform(), yaxis.getTickManager().getAxisTransform())
The "layer" object belongs to the org.jplot2d.element.Layer class. You can extract layers from the plots as:
layers = plot.getLayers()
Creating Graphs
A 2d graph can be created with 2 double array
from array import * x = array('d',[0,1,2,3]) y = array('d',[0,2,1,4]) graph = ef.createXYGraph(x, y) layer.addGraph(graph) # add this graph to layer
Similarly, your code in Java will look as:
double[] x = new double[] {0,1,2,3}; double[] y = new double[] {0,2,1,4}; XYGraph graph = ef.createXYGraph(x, y); layer.addGraph(graph) # add this graph to layer
The "layer" object belongs to the org.jplot2d.element.XYGraph class. You can customize the graph using the methods:
graph.setColor(Color.GREEN); graph.setLineVisible(False); graph.setSymbolVisible(True); graph.setSymbolShape(SymbolShape.SQUARE);
Look at the org.jplot2d.element.XYGraph class.
See the org.jplot2d.util.SymbolShape class.
Data points can have errors bars in X and Y. Create a XYGraph with the given x/y array, x low/high error array and y low/high error array, use this method:
graph=ef.createXYGraph(x_array, y_array, xErrorLow, xErrorHigh, yErrorLow, yErrorHigh, name)
Creating Annotations
There are several kind of annotations can be created
- symbol annotation A point annotation with a symbol and a text string
- horizontal line annotation A horizontal line annotation to highlight a value.
- vertical line annotation A vertical line annotation to highlight a value.
- horizontal strip annotation A horizontal strip annotation to highlight a range.
- vertical strip annotation A vertical strip annotation to highlight a range.
- rectangle annotation A rectangle annotation to highlight a area.
The "annotations" objects belong to the org.jplot2d.element.Annotation class. Look at how the annotations can be made:
ann0 = ef.createSymbolAnnotation(x, y, "text annotation") # symbol annotation ann1 = ef.createHLineAnnotation(y) # horizontal line annotation ann2 = ef.createHStripAnnotation(y1, y2) # horizontal strip annotation layer.addAnnotation(annotation) # Adding an annotation to a layer