Classic chart: X axis questions

UPDATE:
Question #2 has been answered. I’m still looking for an answer to #1.

In a classic chart…

  1. Is it possible to have the time and date display in the X axis? It’s only displaying the time, which isn’t the most helpful when a run spans more than one day.

  2. Is it possible to have the chart NOT plot gaps in time? We had a run shut down one day and start up two days later. That gap in time is on the chart. So all the temperatures, that changed significantly from shut down to start up, have a straight line that goes from their old to their new values, and the straight line spans two days. It looks very awkward.

Notice my awesome mouse hand writing…

1)It’s possible to zoom out the X-axis in the Client (also in the Preview Mode of the Designer, for that matter) by right clicking on the chart, and selecting Zoom Out > Range axis. Do this once or twice and you should be able to zoom out over a couple days. You can zoom back in after if need be.

  1. If there isn’t any data in the Dataset for that time frame, you can go into the Chart Customizer, select your Dataset from the Dataset Properties tab, and change the Type Property to Discontinuous Lines. This should create a gap in your data (i.e. no random straight lines).

If there IS data from that time period, you will have to use some crafty SQL query to selectively leave out the down time.

Thanks, pscott. I believe no. 2 in your reply is what I’m looking for. At least in this case, I’m not allowing end-users to zoom in and out of the chart. I’m feeding the chart only the data from the current run from a SQL view. And no, there is no data in the data set from the time gap I’m talking about here.

As for my first question, I still don’t have an answer. Look at the screenshot in my first post. It only shows the time on the X axis. I’d like it to display date and time, not just time. Anyone?

The chart does its best to format the date/time on the x-axis based on how much you have zoomed in. It’s not always perfect. :slight_smile:

Go to Chart Customizer > X-Axes > and scroll to the bottom. You’ll see “Display Date in Title” Enabling this will display the date below your x-axis, which will probably give your users the information they want.

Thanks for the reply. But that actually doesn’t give me the information I need. If a run spans multiple days, it only displays one of those dates. This is why I’d like it right in with the time on the X axis.

I had a similar problem with a bar chart and posted a possible solution here.
I should be possible to adjust this for the classic chart, if you are a bit experienced in java programming.

EDIT:
I just realized that things changed bit in 7.6. The solution posted above for the StatusChart is not working anymore, since there is no reliable event to trigger the custom script.
Good news is that we now have the ‘configureChart’ extension function for the classic chart, that seems to be made exactly for this situation (IA team: Can we have this for other chart types also?).

Put the following code in the configureChart function:

def configureChart(self, chart):
	import app
	app.chartUtils.setDateTickUnits(chart, "Displaying %1$td.%1$tm.%1$tY %1$tH:%1$tM to %2$td.%2$tm.%2$tY %2$tH:%2$tM")

and create the app.chartUtils script module with the code below. You can adjust the tick units in the getDefaultTickUnits() method. The result will be something like this:
[attachment=0]custom-date-axis.png[/attachment]

# module app.chartUtils
global app
import app

# Constants for axis
DOMAIN_AXIS = 0
RANGE_AXIS = 1

# Replaces all DateAxis in the given chart with a custom axis
# Call this method from the configureChart extension function
# Parameters:
#  chart:	The JFreeChart object
#  label:	A custom axis label. Java's String.format method is used to format this label.
#			Available format args: %1$ - start Date, %2$ end Date
#  axis:	app.chartUtils.DOMAIN_AXIS (default) or app.chartUtils.RANGE_AXIS
#  units:	An org.jfree.chart.axis.TickUnits object (see getDefaultTickUnits())
def setDateTickUnits(chart, label = None, axis = DOMAIN_AXIS, units = None):
	
	if units == None:
		units = app.chartUtils.getDefaultTickUnits()
	
	# Apply the new tick units to the chart
	plot = chart.getPlot()
	
	# Iterate all axis
	from org.jfree.chart.axis import DateAxis
	if axis == app.chartUtils.DOMAIN_AXIS:
		axisCount = plot.getDomainAxisCount()
		for index in range(0, axisCount):
			axis = plot.getDomainAxis(index)
			if isinstance(axis, DateAxis):
				customAxis = app.chartUtils.CustomDateAxis(label)
				customAxis.setStandardTickUnits(units)
				customAxis.setConfigFromAxis(axis)
				plot.setDomainAxis(index,customAxis)

# Create a new org.jfree.chart.axis.TickUnits
def getDefaultTickUnits():
	from org.jfree.chart.axis import TickUnits
	from org.jfree.chart.axis import DateTickUnit
	from java.text import SimpleDateFormat
	units = TickUnits()
	
	# Format definitions
	# Formats are created with default timezone and default locale
	# format.setTimezone might be used to override the timezone
	# Additional space is added to the format to prevent ticks from being
	# displayed without space (happens sometimes when using anchored layout).
	formatMSec = SimpleDateFormat(" HH:mm:ss SS")
	formatSec = SimpleDateFormat(" HH:mm:ss")
	formatMin = SimpleDateFormat(" HH:mm")
	formatHour = SimpleDateFormat(" HH:mm")
	formatDay = SimpleDateFormat(" dd.MM HH:mm")
	formatMonth = SimpleDateFormat(" dd.MM.yyyy")
	formatYear = SimpleDateFormat(" MMM yyyy")
	
	# Add the units
	units.add(DateTickUnit(DateTickUnit.MILLISECOND, 5, formatMSec))
	units.add(DateTickUnit(DateTickUnit.MILLISECOND, 50, DateTickUnit.MILLISECOND, 5, formatMSec))
	units.add(DateTickUnit(DateTickUnit.MILLISECOND, 250, DateTickUnit.MILLISECOND, 50, formatMSec))
	units.add(DateTickUnit(DateTickUnit.MILLISECOND, 500, DateTickUnit.MILLISECOND, 50, formatMSec))
	units.add(DateTickUnit(DateTickUnit.SECOND, 1, DateTickUnit.MILLISECOND, 50, formatSec))
	units.add(DateTickUnit(DateTickUnit.SECOND, 2, DateTickUnit.MILLISECOND, 250, formatSec))
	units.add(DateTickUnit(DateTickUnit.SECOND, 5, DateTickUnit.MILLISECOND, 250, formatSec))
	units.add(DateTickUnit(DateTickUnit.SECOND, 10, DateTickUnit.MILLISECOND, 500, formatSec))
	units.add(DateTickUnit(DateTickUnit.SECOND, 30, DateTickUnit.SECOND, 2, formatSec))
	units.add(DateTickUnit(DateTickUnit.MINUTE, 1, DateTickUnit.SECOND, 5, formatSec))
	units.add(DateTickUnit(DateTickUnit.MINUTE, 2, DateTickUnit.SECOND, 10, formatMin))
	units.add(DateTickUnit(DateTickUnit.MINUTE, 5, DateTickUnit.SECOND, 30, formatMin))
	units.add(DateTickUnit(DateTickUnit.MINUTE, 10, DateTickUnit.MINUTE, 1, formatMin))
	units.add(DateTickUnit(DateTickUnit.MINUTE, 20, DateTickUnit.MINUTE, 5, formatMin))
	units.add(DateTickUnit(DateTickUnit.MINUTE, 30, DateTickUnit.MINUTE, 5, formatMin))
	units.add(DateTickUnit(DateTickUnit.HOUR, 1, DateTickUnit.MINUTE, 5, formatHour))
	units.add(DateTickUnit(DateTickUnit.HOUR, 2, DateTickUnit.MINUTE, 10, formatHour))
	units.add(DateTickUnit(DateTickUnit.HOUR, 4, DateTickUnit.MINUTE, 30, formatHour))
	units.add(DateTickUnit(DateTickUnit.HOUR, 6, DateTickUnit.HOUR, 1, formatDay))
	units.add(DateTickUnit(DateTickUnit.HOUR, 12, DateTickUnit.HOUR, 2, formatDay))
	units.add(DateTickUnit(DateTickUnit.DAY, 1, DateTickUnit.HOUR, 4, formatDay))
	units.add(DateTickUnit(DateTickUnit.DAY, 2, DateTickUnit.HOUR, 4, formatDay))
	units.add(DateTickUnit(DateTickUnit.DAY, 7, DateTickUnit.DAY, 1, formatDay))
	units.add(DateTickUnit(DateTickUnit.DAY, 14, DateTickUnit.DAY, 1, formatDay))
	units.add(DateTickUnit(DateTickUnit.MONTH, 1, DateTickUnit.DAY, 1, formatDay))
	units.add(DateTickUnit(DateTickUnit.MONTH, 2, DateTickUnit.DAY, 7, formatMonth))
	units.add(DateTickUnit(DateTickUnit.MONTH, 3, DateTickUnit.DAY, 14, formatMonth))
	units.add(DateTickUnit(DateTickUnit.MONTH, 6, DateTickUnit.MONTH, 1, formatMonth))
	units.add(DateTickUnit(DateTickUnit.YEAR, 1, DateTickUnit.MONTH, 1, formatYear))
	units.add(DateTickUnit(DateTickUnit.YEAR, 2, DateTickUnit.MONTH, 3, formatYear))
	
	return units
 	
# Override DateAxis#getLabel to return min & max date in custom format
from org.jfree.chart.axis import DateAxis
class CustomDateAxis(DateAxis):
	def __init__(self, label):
		self.customLabel = label
	
	def getLabel(self):
		if self.customLabel == None:
			return super(DateAxis, self)
		else:	
			from java.lang import String
			minDate = super(app.chartUtils.CustomDateAxis, self).getMinimumDate()
			maxDate = super(app.chartUtils.CustomDateAxis, self).getMaximumDate()
			# Modify the format given here, ore add additional logic to change according to the range
			return String.format(self.customLabel, minDate, maxDate)
		
	# Copy the config from another axis
	def setConfigFromAxis(self, other):
		from org.jfree.chart.axis import DateAxis
		super(DateAxis, self).setLabelAngle(other.labelAngle)
		super(DateAxis, self).setLabelFont(other.labelFont)
		super(DateAxis, self).setLabelPaint(other.labelPaint)

		super(DateAxis, self).setTickLabelFont(other.tickLabelFont)
		super(DateAxis, self).setTickLabelPaint(other.tickLabelPaint)
		super(DateAxis, self).setTickLabelsVisible(other.tickLabelsVisible)
		super(DateAxis, self).setVerticalTickLabels(other.verticalTickLabels)
		
		super(DateAxis, self).setTickMarkInsideLength(other.tickMarkInsideLength)
		super(DateAxis, self).setTickMarkOutsideLength(other.tickMarkOutsideLength)
		super(DateAxis, self).setTickMarkPaint(other.tickMarkPaint)
		super(DateAxis, self).setTickMarksVisible(other.tickMarksVisible)
			
		super(DateAxis, self).setNegativeArrowVisible(other.negativeArrowVisible)
		super(DateAxis, self).setPositiveArrowVisible(other.positiveArrowVisible)
		super(DateAxis, self).setLowerMargin(other.lowerMargin)
		super(DateAxis, self).setUpperMargin(other.upperMargin)
1 Like

Wow that works awesome! This has been driving me crazy for awhile now. Thanks!