I played around with this a little more this morning, and came up with a more flexible approach to changing the tick labels.
First, I added the following method to the beginning of the configureChart extension function to hide the stock labels and create a set of new labels to take their place:
def dynamicLabelCreator(self, chart, rawData):
domainAxis = chart.getCategoryPlot().getDomainAxis()
for row, category in enumerate(chart.getCategoryPlot().getCategories()):
for component in self.getComponents():
if isinstance(component, PMILabel) and component.name == category:
self.remove(component)
domainAxis.setTickLabelPaint(category, Color(0,0,0,0))
customLabel = PMILabel()
labelName = category
customLabel.setName(labelName)
customLabel.setVisible(True)
self.add(customLabel)
rawData = self.rawData
dynamicLabelCreator(self, chart, rawData)
Then, I set the stock labels to a 90 degree orientation to give myself more room at the bottom of the chart, and while experimenting, I found that the bars rendered better if I set the lower margin of the category axis to .1
Finally, I modified the calculateW0 method to set the labels based on the center of the bar minus 1/2 the width of the label. Initially, the result looked good, but as I added more bars, the labels began to overlap:
Consequently, I reduced the number of line breaks, and changed the rotation of the labels. I also decided to go ahead and employ an innate label generator to put the actual values on top of the bars:
Below is the full code. I am certain this will still require quite a bit of tweaking, changing, and refactoring to produce an acceptable product for your usage case, but there should be more than enough directions here to go off of. Good Luck!
Full Code:
def configureChart(self, chart):
from com.inductiveautomation.factorypmi.application.components import PMILabel
from java.awt import Color
from org.jfree.chart.renderer.category import BarRenderer, StandardBarPainter
from java.text import NumberFormat
from org.jfree.chart.labels import StandardCategoryItemLabelGenerator
def dynamicLabelCreator(self, chart, rawData):
domainAxis = chart.getCategoryPlot().getDomainAxis()
for row, category in enumerate(chart.getCategoryPlot().getCategories()):
for component in self.getComponents():
if isinstance(component, PMILabel) and component.name == category:
self.remove(component)
domainAxis.setTickLabelPaint(category, Color(0,0,0,0))
customLabel = PMILabel()
labelName = category
customLabel.setName(labelName)
customLabel.setVisible(True)
customLabel.rotation = 290
self.add(customLabel)
rawData = self.rawData
dynamicLabelCreator(self, chart, rawData)
chart.setTitle("Histogram")
data = self.data
padding = self.width * .25
width = self.width - padding
maxTimeValue = data.getRowCount()-1
chartStartTime = data.getValueAt(0,0)
chartEndTime = data.getValueAt(maxTimeValue,0)
totalTime = system.date.minutesBetween(chartStartTime,chartEndTime)
timeRatio = float(width)/float(totalTime)
scaleRatio = float(self.width)*0.018
class DynamicWidthRenderer(BarRenderer):
def calculateBarW0(BarRenderer, plot, orientation, dataArea, domainAxis, state, row, column):
from com.inductiveautomation.factorypmi.application.components import PMILabel
barStartTime = data.getValueAt(column,0)
barStartingLocation = float(system.date.minutesBetween(chartStartTime, barStartTime))*timeRatio + padding * .5
customLabel = self.getComponent(column)
try:
barEndTime = data.getValueAt((column + 1), 0)
barScaleParameter = float(system.date.minutesBetween(barStartTime, barEndTime))*scaleRatio
customLabel.text = '<html><b><center>WO# ' + str(self.rawData.getValueAt(column,1)) + '<br>' + str(system.date.format(barStartTime, "MM/dd HH:mm:ss")) + '<br>to ' + str(system.date.format(barEndTime, "HH:mm:ss"))
labelOffset = customLabel.width * .5
labelLocation = barStartingLocation+((float(system.date.minutesBetween(barStartTime, barEndTime))*.5)*timeRatio)-labelOffset
except:
barScaleParameter = float(width + padding - barStartingLocation)*scaleRatio
customLabel.text = '<html><b><center>WO# ' + str(self.rawData.getValueAt(column,1)) + '<br>' + str(system.date.format(barStartTime, "MM/dd HH:mm:ss")) + '<br>to ' + '[...]'
labelOffset = customLabel.width * .5
labelLocation = barStartingLocation - (.5 * labelOffset)
heightJustification = float(len(chart.getCategoryPlot().getCategories()[column]))*9
customLabel.setLocation(int(labelLocation), self.height - int(heightJustification))
customLabel.setSize(250,250)
dataArea.width = barScaleParameter
BarRenderer.calculateBarWidth(plot, dataArea, 0, state)
return barStartingLocation
def getItemPaint(BarRenderer, row, column):
if column % 2 == 0:
return Color.blue
else:
return Color.yellow
chart.getCategoryPlot().setRenderer(DynamicWidthRenderer())
numberFormat = NumberFormat.getInstance()
defaultFormat = StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING
labelGenerator = StandardCategoryItemLabelGenerator(defaultFormat, numberFormat)
chart.getCategoryPlot().getRenderer().setBaseItemLabelGenerator(labelGenerator)
chart.getCategoryPlot().getRenderer().setBaseItemLabelsVisible(True)
chart.getCategoryPlot().getRenderer().setBarPainter(StandardBarPainter())
chart.getCategoryPlot().getRenderer().setShadowVisible(False)