Создание плавных кривых в JFreeChart с использованием XYBezierRenderer или XYCardinalSplineRendererJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Создание плавных кривых в JFreeChart с использованием XYBezierRenderer или XYCardinalSplineRenderer

Сообщение Anonymous »

Я пытаюсь создать график с помощью JFreeChart для отображения данных о температуре и влажности. Изначально я использовал XYSplineRenderer, но это вышло за рамки. После исследования переполнения стека я нашел предложение использовать XYBezierRenderer (JFreeChart setAutoRange, когда XYSplineRenderer используется при визуализации). Однако даже при использовании XYBezierRenderer результаты оказались неудовлетворительными, так как были резкие повороты при натяжении 0,05 и точности 5.
Вот код, который я использую для создания диаграммы :

Код: Выделить всё

private JFreeChart createMultiAxisChart(List reportsData, Map attributes, TemperatureStatistics temperatureStats, HumidityStatistics humidityStatistics) {
List reportData = generateDummyData();
XYDataset temperatureDataset = createMultiTemperatureDataset(reportData);
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"Temperature & Humidity",
"Time",
"Temperature (°C)",
temperatureDataset,true,true,false);
XYPlot plot = chart.getXYPlot();
plot.setBackgroundPaint(Color.WHITE);
plot.setDomainGridlinesVisible(true);
plot.setRangeGridlinesVisible(true);
plot.setDomainGridlinePaint(Color.GRAY);
plot.setRangeGridlinePaint(Color.GRAY);

Font axisLabelFont = new Font("SansSerif", Font.BOLD, 12);
Font tickLabelFont = new Font("SansSerif", Font.BOLD, 10);
Color axisLabelColor = Color.BLACK;

DateAxis dateAxis = new DateAxis("Time");
dateAxis.setDateFormatOverride(new SimpleDateFormat("yyyy-MM-dd"));
dateAxis.setAutoTickUnitSelection(true);
dateAxis.setAutoRange(true);
dateAxis.setLabelFont(axisLabelFont);
dateAxis.setTickLabelFont(tickLabelFont);
dateAxis.setLabelPaint(axisLabelColor);
dateAxis.setTickLabelPaint(axisLabelColor);
plot.setDomainAxis(dateAxis);

XYBezierRenderer tempRenderer = new XYBezierRenderer(5,0.05);
for (int i = 0; i < temperatureDataset.getSeriesCount(); i++) {
tempRenderer.setSeriesPaint(i, getSeriesColor(i));
tempRenderer.setSeriesShapesVisible(i, false);
}
plot.setRenderer(0, tempRenderer);

NumberAxis tempAxis = (NumberAxis) plot.getRangeAxis();
tempAxis.setLabelFont(axisLabelFont);
tempAxis.setTickLabelFont(tickLabelFont);
tempAxis.setLabelPaint(axisLabelColor);
tempAxis.setTickLabelPaint(axisLabelColor);
double minTemperature = calculateMinTemperature(temperatureStats);
double maxTemperature = calculateMaxTemperature(temperatureStats);
tempAxis.setRange(0, 100);
tempAxis.setAutoRangeIncludesZero(false);
tempAxis.setLowerMargin(0.05);
tempAxis.setUpperMargin(0.05);

XYDataset humidityDataset = createMultiHumidityDataset(reportData);
NumberAxis humidityAxis = new NumberAxis("Humidity (%)");

double minHumidity = calculateMinHumidity(humidityStatistics);
double maxHumidity = calculateMaxHumidity(humidityStatistics);
humidityAxis.setLabelFont(axisLabelFont);
humidityAxis.setTickLabelFont(tickLabelFont);
humidityAxis.setLabelPaint(axisLabelColor);
humidityAxis.setTickLabelPaint(axisLabelColor);
humidityAxis.setRange(0, 100);
humidityAxis.setTickUnit(new NumberTickUnit(10));
humidityAxis.setUpperMargin(0.05);
humidityAxis.setLowerMargin(0.05);
humidityAxis.setAutoRangeIncludesZero(false);

plot.setRangeAxis(1, humidityAxis);
plot.setDataset(1, humidityDataset);
plot.mapDatasetToRangeAxis(1, 1);

XYBezierRenderer humidityRenderer = new XYBezierRenderer(5,0.05);
for (int i = 0; i < humidityDataset.getSeriesCount(); i++) {
humidityRenderer.setSeriesPaint(i, getSeriesColor(i + temperatureDataset.getSeriesCount()));
humidityRenderer.setSeriesShapesVisible(i, false);
}
plot.setRenderer(1, humidityRenderer);

LegendItemCollection legendItems = new LegendItemCollection();
XYItemRenderer renderer0 = plot.getRenderer(0);
XYItemRenderer renderer1 = plot.getRenderer(1);

for (int i = 0; i < temperatureDataset.getSeriesCount(); i++) {
Paint seriesPaint = renderer0.getSeriesPaint(i);
LegendItem legendItem = new LegendItem(
temperatureDataset.getSeriesKey(i).toString(),
"",
"",
"",
new Rectangle(10, 10),
seriesPaint
);
legendItem.setLabelPaint(seriesPaint);
legendItems.add(legendItem);
}

for (int i = 0; i < humidityDataset.getSeriesCount();  i++) {
Paint seriesPaint = renderer1.getSeriesPaint(i);
LegendItem legendItem = new LegendItem(
humidityDataset.getSeriesKey(i).toString(),
"",
"",
"",
new Rectangle(10, 10),
seriesPaint
);
legendItem.setLabelPaint(seriesPaint);
legendItems.add(legendItem);
}

plot.setFixedLegendItems(legendItems);
return chart;
}
и пользовательские данные генерируются как

Код: Выделить всё

private List generateDummyData() {
List dummyData = new ArrayList();
Random random = new Random();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd   HH:mm:ss");
Calendar calendar = Calendar.getInstance();calendar.add(Calendar.DAY_OF_YEAR, -30); // Start 30 days ago    // Generate data every 7.5 hours (96 points over 30 days)
int hoursPerReading = 7;
int minutesPerReading = 30;

for (int i = 0; i < 96; i++) {
EntityAuditDto dto = new EntityAuditDto();

// Generate timestamp
calendar.add(Calendar.HOUR, hoursPerReading);
calendar.add(Calendar.MINUTE, minutesPerReading);
dto.setDateTime(dateFormat.format(calendar.getTime()));

// Generate data with realistic variations
double timeProgress = i / 95.0; // Normalized time progress (0 to 1)
double dailyCycle = Math.sin(2 * Math.PI * timeProgress * 4); // 4 complete cycles over the period
double weeklyCycle = Math.sin(2 * Math.PI * timeProgress * (4.0/7)); // 4/7 cycles (4 weeks) over the period

// Generate values for each sensor within specified ranges
double t1Base = 55 + 35 * dailyCycle + 5 * weeklyCycle; // 10 to 100
double t2Base = 45 + 10 * dailyCycle + 3 * weeklyCycle; // 30 to 60
double t3Base = 15 + 10 * dailyCycle + 3 * weeklyCycle; // 0 to 30
double h1Base = 75 + 20 * dailyCycle + 3 * weeklyCycle; // 50 to 100
double h2Base = 35 + 10 * dailyCycle + 3 * weeklyCycle; // 20 to 50

// Add random noise and ensure values are within specified ranges
dto.setT1(String.format("%.2f", clamp(t1Base + random.nextGaussian() * 3, 10, 100)));
dto.setT2(String.format("%.2f", clamp(t2Base + random.nextGaussian() * 2, 30, 60)));
dto.setT3(String.format("%.2f", clamp(t3Base + random.nextGaussian() * 2, 0, 30)));
dto.setH1(String.format("%.2f", clamp(h1Base + random.nextGaussian() * 3, 50, 100)));
dto.setH2(String.format("%.2f", clamp(h2Base + random.nextGaussian() * 2, 20, 50)));

dummyData.add(dto);
}

return dummyData;
}

// Helper method to clamp values between min and max
private double clamp(double value, double min, double max) {
return Math.max(min, Math.min(max, value));
}` .
Результаты для приведенных выше данных соответствуют результатам приведенного выше кода.
может ли кто-нибудь помочь?
Я пробовал использовать различные значения точности и натяжения. Но, наконец, XYBezierRenderer(5,0.05) добился лучших результатов. https://www.jfree.org/forum/viewtopic.php?t=116831 здесь было предложено использовать собственный класс XYCardinalSplineRenderer, который я попробовал и работал несколько лучше. результаты с ним были хорошие при напряжении 0,05 и сегментах 16? . Я думаю, что решение было еще в 2014 году и не включено в jfreechart. Может ли кто-нибудь помочь мне с этим?


Подробнее здесь: https://stackoverflow.com/questions/790 ... dinalsplin
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»