1

The minor ticks in Chaco are always omitted: enter image description here

This is not always convinient. Is it possible to have minor ticks in Chaco like ones in matplotlib:

enter image description here

Haven't found anything related.. Thanks.

funnyp0ny
  • 298
  • 1
  • 12

1 Answers1

1

Edit: This feature has now been added to Chaco 4.6, so if you're using this version or later, use the following similar code. If not see the original post below. Also see the documentation here and another example here.

if __name__ == "__main__":
    from traits.etsconfig.api import ETSConfig
    ETSConfig.toolkit = 'qt4'
    #
    import warnings
    warnings.filterwarnings(action = "ignore", category = FutureWarning, module="chaco")
    warnings.filterwarnings(action = "ignore", category = FutureWarning, module="traits")
#
from PySide import QtGui, QtCore
import numpy as np
from enable.api import Component, Container, Window
from chaco.api import *
import sys
#
class ChacoPlot(QtGui.QWidget):
    def __init__(self, parent=None):
        super(ChacoPlot, self).__init__(parent)
        #
        self.container = OverlayPlotContainer(padding=40)
        #
        self.enableWindow = Window(self, -1, component=self.container)
        windowLayout = QtGui.QVBoxLayout(self)
        windowLayout.addWidget(self.enableWindow.control)
        #
        self.xRange = DataRange1D()
        self.yRange = DataRange1D()
        #
        self.xMapper = LinearMapper(range=self.xRange)
        self.yMapper = LinearMapper(range=self.yRange)
        #
        self.plots = {}
        # keep a list of plots added to the container
    #
    def setMinimumSize(self, width, height):
        self.enableWindow.control.setMinimumSize(width, height)
    #
    def addLine(self, name, plotType):
        xSource = ArrayDataSource([0])
        ySource = ArrayDataSource([0])
        #
        self.xRange.add(xSource)
        self.yRange.add(ySource)
        #
        index_mapper = self.xMapper
        value_mapper = self.yMapper
        #
        # plotType is a class name
        plot = plotType(    index = xSource,
                            value = ySource,
                            index_mapper = index_mapper,
                            value_mapper = value_mapper,
                            visible = False
                       )
        #
        self.container.add(plot)
        #
        self.plots[name] = {'plot':plot, 'xSource':xSource, 'ySource':ySource}
    #
    def updateLine(self, name, xData, yData):
        plot = self.plots[name]
        #
        if np.array(xData).size != 0:
            plot['plot'].visible = True
        else:
            plot['plot'].visible = False
            xData = [0]
            yData = [0]
        #
        plot['xSource'].set_data(xData)
        plot['ySource'].set_data(yData)
    #
    def addAxis(self, plotName, orientation):
        plot = self.plots[plotName]['plot']
        #
        if orientation == 'top' or orientation == 'bottom':
            mapper = self.xMapper
        if orientation == 'left' or orientation == 'right':
            mapper = self.yMapper
        #
        axis = PlotAxis(plot, orientation=orientation, mapper=mapper)
        plot.overlays.append(axis)
        #
        return axis
    #
    def addMinorAxis(self, plotName, orientation):
        plot = self.plots[plotName]['plot']
        #
        if orientation == 'top' or orientation == 'bottom':
            mapper = self.xMapper
            range = self.xRange
        if orientation == 'left' or orientation == 'right':
            mapper = self.yMapper
            range = self.yRange
        #
        newAxis = MinorPlotAxis(plot, orientation=orientation, mapper=mapper)
        plot.overlays.append(newAxis)
        #
        return axis
    #
#
if __name__ == "__main__":
    appQT = QtGui.QApplication.instance()
    #
    x1 = np.arange(300)/18.0
    y1 = np.sin(x1)
    x2 = np.arange(300)/18.0
    y2 = 2.0*np.cos(x2)
    #
    plot = ChacoPlot()
    plot.setMinimumSize(400,300)
    #
    plot.addLine('line1', LinePlot)
    plot.addLine('line2', LinePlot)
    plot.updateLine('line1', x1, y1)
    plot.updateLine('line2', x2, y2)
    #
    plot.addAxis('line1', 'bottom')
    plot.addAxis('line1', 'left')
    plot.addMinorAxis('line1', 'bottom')
    plot.addMinorAxis('line1', 'left')
    #
    plot.show()
    appQT.exec_()

Original: Chaco doesn't have this feature specifically, but you can add minor ticks by adding an extra PlotAxis. You need to modify a few properties of the axis:

  • tick_generator - This object defines the position of the ticks
  • tick_label_formatter - This function returns the tick label string for a given tick label value
  • tick_in and tick_out - These numbers define the size of the ticks (in and out of the axis)

Here's an example. It's a lot of code, but it's fairly straightforward. Although it is common for people to make plots using the Plot helper class, I like to create plots manually since it's much easier to customize. Anyways hope it helps.

if __name__ == "__main__":
    from traits.etsconfig.api import ETSConfig
    ETSConfig.toolkit = 'qt4'
    #
    import warnings
    warnings.filterwarnings(action = "ignore", category = FutureWarning, module="chaco")
    warnings.filterwarnings(action = "ignore", category = FutureWarning, module="traits")
#
from PySide import QtGui, QtCore
import numpy as np
from enable.api import Component, Container, Window
from chaco.api import *
import sys
#
class ChacoPlot(QtGui.QWidget):
    def __init__(self, parent=None):
        super(ChacoPlot, self).__init__(parent)
        #
        self.container = OverlayPlotContainer(padding=40)
        #
        self.enableWindow = Window(self, -1, component=self.container)
        windowLayout = QtGui.QVBoxLayout(self)
        windowLayout.addWidget(self.enableWindow.control)
        #
        self.xRange = DataRange1D()
        self.yRange = DataRange1D()
        #
        self.xMapper = LinearMapper(range=self.xRange)
        self.yMapper = LinearMapper(range=self.yRange)
        #
        self.plots = {}
        # keep a list of plots added to the container
    #
    def setMinimumSize(self, width, height):
        self.enableWindow.control.setMinimumSize(width, height)
    #
    def addLine(self, name, plotType):
        xSource = ArrayDataSource([0])
        ySource = ArrayDataSource([0])
        #
        self.xRange.add(xSource)
        self.yRange.add(ySource)
        #
        index_mapper = self.xMapper
        value_mapper = self.yMapper
        #
        # plotType is a class name
        plot = plotType(    index = xSource,
                            value = ySource,
                            index_mapper = index_mapper,
                            value_mapper = value_mapper,
                            visible = False
                       )
        #
        self.container.add(plot)
        #
        self.plots[name] = {'plot':plot, 'xSource':xSource, 'ySource':ySource}
    #
    def updateLine(self, name, xData, yData):
        plot = self.plots[name]
        #
        if np.array(xData).size != 0:
            plot['plot'].visible = True
        else:
            plot['plot'].visible = False
            xData = [0]
            yData = [0]
        #
        plot['xSource'].set_data(xData)
        plot['ySource'].set_data(yData)
    #
    def addAxis(self, plotName, orientation):
        plot = self.plots[plotName]['plot']
        #
        if orientation == 'top' or orientation == 'bottom':
            mapper = self.xMapper
        if orientation == 'left' or orientation == 'right':
            mapper = self.yMapper
        #
        axis = PlotAxis(plot, orientation=orientation, mapper=mapper)
        plot.overlays.append(axis)
        #
        return axis
    #
    def addMinorAxis(self, plotName, orientation):
        plot = self.plots[plotName]['plot']
        #
        if orientation == 'top' or orientation == 'bottom':
            mapper = self.xMapper
            range = self.xRange
        if orientation == 'left' or orientation == 'right':
            mapper = self.yMapper
            range = self.yRange
        #
        newAxis = PlotAxis(plot, orientation=orientation, mapper=mapper)
        plot.overlays.append(newAxis)
        #
        newAxis.tick_generator = MinorTickGenerator()
        #
        newAxis.tick_label_formatter  = lambda x: ''
        newAxis.tick_in  = 2
        newAxis.tick_out = 2
    #
#
class MinorTickGenerator(AbstractTickGenerator):
    def __init__(self):
        super(MinorTickGenerator, self).__init__()
    #
    def get_ticks(self, data_low, data_high, bounds_low, bounds_high, interval, use_endpoints=False, scale='linear'):
        interval = interval
        #
        if interval == 'auto':
            interval = auto_interval(data_low, data_high)/5.0
        #
        return auto_ticks(data_low, data_high, bounds_low, bounds_high, interval, use_endpoints)
    #
#
if __name__ == "__main__":
    appQT = QtGui.QApplication.instance()
    #
    x1 = np.arange(300)/18.0
    y1 = np.sin(x1)
    x2 = np.arange(300)/18.0
    y2 = 2.0*np.cos(x2)
    #
    plot = ChacoPlot()
    plot.setMinimumSize(400,300)
    #
    plot.addLine('line1', LinePlot)
    plot.addLine('line2', LinePlot)
    plot.updateLine('line1', x1, y1)
    plot.updateLine('line2', x2, y2)
    #
    plot.addAxis('line1', 'bottom')
    plot.addAxis('line1', 'left')
    plot.addMinorAxis('line1', 'bottom')
    plot.addMinorAxis('line1', 'left')
    #
    plot.show()
    appQT.exec_()

enter image description here

Steve
  • 542
  • 1
  • 4
  • 12