How can I pass a variable from one class to another class and use it as a value in JFreeChart [duplicate] - jfreechart

This question already has an answer here:
I have a bar chart which I want to update and I tried the revalidate and repaint methods but with no success
(1 answer)
Closed 8 years ago.
I want to generate a bar graph based from user inputs but, I tried passing it from my main class to the class where I coded my graph and it doesn't work.
here's a part of my main class. It's were I will get the value.
public double computeE1() {
double x1 = sFrame.s1;
double x2 = tFrame.t1;
double x3 = fFrame.f1;
E1 = 5.278 + ((-0.172)*x1) + ((-0.197)*x2) + ((-0.191)*x3);
return E1;
}
and here's my JFreeChart class
public class BarChart extends ApplicationFrame {
GUImain gui; //main class
public BarChart(final String title)
{
super(title);
final CategoryDataset dataset = createDataset();
final JFreeChart chart = createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(500,270));
setContentPane(chartPanel);
}
private CategoryDataset createDataset()
{
double e1 = gui.E1;
double e2 = gui.E2;
double e3 = gui.E3;
double e4 = gui.E4;
DefaultCategoryDataset ds = new DefaultCategoryDataset();
ds.addValue(e1, "asdas", null);
ds.addValue(e2, "asdasda", null);
ds.addValue(e3, "sar", null);
ds.addValue(e4, "asda", null);
return ds;
}

This can be very confusing when you are just learning Java. The trick is to have a "control" class, which controls and coordinates the other elements of the program (ie analytics, ui, etc). Your your case, I'd probably try to include the class that has your analytics into the class that you're using for your UI... Is the analytics class stateless? https://softwareengineering.stackexchange.com/.../whats-the-difference-between-stateful-and-stateless

Related

How to adjust colors in the UI of OptaPlanner?

I am currently using the OptaPlanner's job schedule algorithm to create a certain planning. I want every execution mode used in the planning to be shown in a different color (instead of all different projects to be shown in different colors). Is it possible to implement this and if so, how? I have been searching through the code for a while now and have no idea how to do this.
This cannot be done easily with the Project Scheduling Swing application that's part of OptaPlanner project. It plots the data using JFreeChart and I couldn't find a simple way to associate metadata (like color) with the data that's being plotted.
You can override YIntervalRenderer behavior to return color of your choice based on data item's row (seriesIndex) and column (item's index in the series) but you have to keep the mapping between execution mode and [row, column] yourself, which is cumbersome.
Here's an example of modified ProjectJobSchedulingPanel that does the above:
public class ProjectJobSchedulingPanel extends SolutionPanel<Schedule> {
private static final Logger logger = LoggerFactory.getLogger(ProjectJobSchedulingPanel.class);
private static final Paint[] PAINT_SEQUENCE = DefaultDrawingSupplier.DEFAULT_PAINT_SEQUENCE;
public static final String LOGO_PATH = "/org/optaplanner/examples/projectjobscheduling/swingui/projectJobSchedulingLogo.png";
public ProjectJobSchedulingPanel() {
setLayout(new BorderLayout());
}
#Override
public void resetPanel(Schedule schedule) {
removeAll();
ChartPanel chartPanel = new ChartPanel(createChart(schedule));
add(chartPanel, BorderLayout.CENTER);
}
private JFreeChart createChart(Schedule schedule) {
YIntervalSeriesCollection seriesCollection = new YIntervalSeriesCollection();
Map<Project, YIntervalSeries> projectSeriesMap = new LinkedHashMap<>(
schedule.getProjectList().size());
ExecutionMode[][] executionModeByRowAndColumn = new ExecutionMode[schedule.getProjectList().size()][schedule.getAllocationList().size()];
YIntervalRenderer renderer = new YIntervalRenderer() {
#Override
public Paint getItemPaint(int row, int column) {
ExecutionMode executionMode = executionModeByRowAndColumn[row][column];
logger.info("getItemPaint: ExecutionMode [{},{}]: {}", row, column, executionMode);
return executionMode == null
? TangoColorFactory.ALUMINIUM_5
: PAINT_SEQUENCE[(int) (executionMode.getId() % PAINT_SEQUENCE.length)];
}
};
Map<Project, Integer> seriesIndexByProject = new HashMap<>();
int maximumEndDate = 0;
int seriesIndex = 0;
for (Project project : schedule.getProjectList()) {
YIntervalSeries projectSeries = new YIntervalSeries(project.getLabel());
seriesCollection.addSeries(projectSeries);
projectSeriesMap.put(project, projectSeries);
renderer.setSeriesShape(seriesIndex, new Rectangle());
renderer.setSeriesStroke(seriesIndex, new BasicStroke(3.0f));
seriesIndexByProject.put(project, seriesIndex);
seriesIndex++;
}
for (Allocation allocation : schedule.getAllocationList()) {
int startDate = allocation.getStartDate();
int endDate = allocation.getEndDate();
YIntervalSeries projectSeries = projectSeriesMap.get(allocation.getProject());
int column = projectSeries.getItemCount();
executionModeByRowAndColumn[seriesIndexByProject.get(allocation.getProject())][column] = allocation.getExecutionMode();
logger.info("ExecutionMode [{},{}] = {}", seriesIndexByProject.get(allocation.getProject()), column, allocation.getExecutionMode());
projectSeries.add(allocation.getId(), (startDate + endDate) / 2.0,
startDate, endDate);
maximumEndDate = Math.max(maximumEndDate, endDate);
}
NumberAxis domainAxis = new NumberAxis("Job");
domainAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
domainAxis.setRange(-0.5, schedule.getAllocationList().size() - 0.5);
domainAxis.setInverted(true);
NumberAxis rangeAxis = new NumberAxis("Day (start to end date)");
rangeAxis.setRange(-0.5, maximumEndDate + 0.5);
XYPlot plot = new XYPlot(seriesCollection, domainAxis, rangeAxis, renderer);
plot.setOrientation(PlotOrientation.HORIZONTAL);
// Uncomment this to use Tango color sequence instead of JFreeChart default sequence.
// This results in color per project mode.
// DefaultDrawingSupplier drawingSupplier = new DefaultDrawingSupplier(
// TangoColorFactory.SEQUENCE_1,
// DefaultDrawingSupplier.DEFAULT_FILL_PAINT_SEQUENCE,
// DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE,
// DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE,
// DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
// DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE);
// plot.setDrawingSupplier(drawingSupplier);
return new JFreeChart("Project Job Scheduling", JFreeChart.DEFAULT_TITLE_FONT, plot, true);
}
}
Result:
Another approach would be to implement JFreeChart interfaces and make custom Dataset and Renderer so that you could plot Allocations directly. Similar to the Gantt chart implementaion in JFreeChart.
Or write your custom UI from the ground up. Depends op how much effort you're willing to put into it :)

JFReeCharts XYPlot is it possible to change shapes inside legends

lt.setPosition(RectangleEdge.BOTTOM);
lt.setItemFont(old);
// get the range axis and add the $ symbol for the values
NumberAxis na = (NumberAxis) plot.getRangeAxis();
// set font
na.setLabelFont(fAxisFont);
na.setTickLabelFont(fAxisFont);
na.setAutoRange(true);
The above is my code snippet.Can anyone tell how to to chang shapes inside legends
I'm using the following workaround:
StandardXYItemRenderer renderer = new StandardXYItemRenderer() {
private static final long serialVersionUID = 0L;
#Override
public LegendItem getLegendItem(int datasetIndex, int series) {
LegendItem legend = super.getLegendItem(datasetIndex,
series);
return new LegendItem(legend.getLabel(),
legend.getDescription(), legend.getToolTipText(),
legend.getURLText(), Plot.DEFAULT_LEGEND_ITEM_BOX,
legend.getFillPaint());
}
};
...
plot.setRenderer(renderer);
Result:
A LegendItem infers its Shape from the corresponding series, which can be changed as shown here. This related example shows one way to render a LegendItem in an external component.

Plotting time in milliseconds - JFreeChart (Step Chart)

I'm trying to plot a step chart with the following properties:
x-axis: Time (ms) [Actual data contains this as a double value]
y-axis: Another value stored as an integer.
I'm filling up the dataset as follows:
private XYSeries populateStepChartDataSet(HashMap<Double, Integer> dataGrid){
XYSeries xySeries = new XYSeries("Step Plot", true, true);
if(dataGrid != null){
for (Double timeStamp : dataGrid.keySet()) {
xySeries.add(timeStamp, dataGrid.get(timeStamp));
}
}
return xySeries;
}
And the section where I create the plot is as follows:
final XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(populateStepChartDataSet(dspDataGrid));
final JFreeChart chart = ChartFactory.createXYStepChart(
title,
xAxisLabel, yAxisLabel,
dataset,
PlotOrientation.VERTICAL,
true, // legend
true, // tooltips
false // urls
);
What I expect is the plot to show time in ms at the x-axis but this value is getting converted to some weird time. Here's how the plot looks
Can someone please help me get back the timestamp in ms format for the x-axis?
It looks like the x Axis is formatting as a date one way of adressing this is to provide a NumberFormatOverride
Add this code after your chart is created:
XYPlot plot = (XYPlot)chart.getPlot();
plot.setDomainAxis(0, new NumberAxis());
NumberAxis axis = (NumberAxis) plot.getDomainAxis();
axis.setNumberFormatOverride( new NumberFormat(){
#Override
public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
return new StringBuffer(String.format("%f", number));
}
#Override
public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
return new StringBuffer(String.format("%9.0f", number));
}
#Override
public Number parse(String source, ParsePosition parsePosition) {
return null;
}
} );
axis.setAutoRange(true);
axis.setAutoRangeIncludesZero(false);
You shold then get this chart:
FYI, use entrySet() whenever you iterate through a Map instead of iterating through the keySet() and then getting the value for each key.

Jfreechart get Mouse Co-ordinates

I have been trying to get current Mouse Co-ordinates in a JfreeChart and found that the following solution was working partially
JFreeChart get mouse coordinates
I have been using OHLC Dataset to draw the chart and while I could get the RangeAxis properly (meaning in the subplot values), I couldn't make anything out of the value recieved for the X-Axis from the above example.
I am sure that I am receiving the values in some other format (not the displayed date format), anyone could point out what I am doing wrong?
Got it solved after few hours of experiment. Here is the code for a complete MouseMotionListener. Just added this to the chartPanel and voila! - it works!
The chartY returns proper value of Y-Axis and the dateString returns complete date. Tried it in an OHLC Chart and seems proper.
MouseMotionListener mouselisten = new MouseMotionListener() {
public void mouseDragged(MouseEvent e) {
//
}
public void mouseMoved(MouseEvent e) {
Point2D p = e.getPoint();
Rectangle2D plotArea = chartPanel.getScreenDataArea();
XYPlot plot = (XYPlot) chart.getPlot(); // your plot
double chartX = plot.getDomainAxis().java2DToValue(p.getX(), plotArea, plot.getDomainAxisEdge());
double chartY = plot.getRangeAxis().java2DToValue(p.getY(), plotArea, plot.getRangeAxisEdge());
DecimalFormat dfT = new DecimalFormat("00");
GregorianCalendar gc = new GregorianCalendar();
long lDte = (long)chartX;
Date dtXX = new Date(lDte);
gc.setTime(dtXX);
String sDD = dfT.format(Double.valueOf(String.valueOf(gc.get(GregorianCalendar.DAY_OF_MONTH))));
String sMM = dfT.format(Double.valueOf(String.valueOf(gc.get(GregorianCalendar.MONTH)+1)));
String sYY = dfT.format(Double.valueOf(String.valueOf(gc.get(GregorianCalendar.YEAR))));
String dateString = sDD +"/"+ sMM +"/"+ sYY;
}
};

How can I databind dynamically loaded DataGridViews?

I'm developing a Windows Forms application in VS2008. I want to display a unknown, but small number of DataGridViews on a form, using code like this:
foreach (QueryFilter f in Query.Filter)
{
DataGridView grid = CreateGridView(String.Format("GridView{0}", filters.Count));
grid.Location = new System.Drawing.Point(3, 9 + (filters.Count * grid.Height + 9));
BindingList<QueryFilterNode> nodes = new BindingList<QueryFilterNode>();
foreach (QueryFilterNode node in f)
nodes.Add(node);
grid.DataSource = nodes;
panel1.Controls.Add(grid);
filters.Add(nodes);
}
The grid(s) are added to the panel, but the data inside is not displayed. My guess is setting the DataSource property doesn't actualy bind the grid, because (for example) the dataGridView_ColumnAdded event is not fired.
QueryFilter and QueryFilterNode are just POCO's and contain data of course.
For completeness sake the construction of the DataGridView:
private DataGridView CreateGridView(string name)
{
DataGridView grid = new DataGridView();
grid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
grid.Name = name;
grid.Size = new System.Drawing.Size(484, 120);
grid.ColumnAdded += new System.Windows.Forms.DataGridViewColumnEventHandler(this.dataGridView_ColumnAdded);
return grid;
}
Hmm, it seems it was my own mistake.
QueryFilterNode, used as datasource ( BindingList<QueryFilterNode> ) wasn't a POCO but a datacontract. Snippet:
[DataContract(Name = "QueryFilterNode")]
public class QueryFilterNode
{
[DataMember(IsRequired = true)]
public string FieldCode;
For some reason these cannot be databound. I used a simple class like this in my BindingList and it just worked.
class QueryFilterNodeSimple
{
public string FieldCode
{ get; set; }

Resources