[vtkusers] Positioning titles within vtkAxis

Eric E. Monson emonson at cs.duke.edu
Tue Dec 7 13:05:44 EST 2010


Hey Daniel,

There seems to be something wrong with the painting for vtkAxis when used by itself in a scene. I'm not sure why we don't see this behavior when these axes are used within the charts. Hopefully Marcus will be able to take a look. You can see the problem even in the attached simple Python script.

One thing I noticed that maybe Marcus can comment on: Things like vtkChartXY do an Update on themselves before Paint. If in this script you don't call Update explicitly on the axis objects they paint the axis line and title, but not the ticks and their labels. Maybe it would be good to add and Update call at the beginning of vtkAxis::Paint?

Daniel, something you might want to consider instead of the method you're using now is a trick others are using for vtkScalarsToColorsItem and its subclasses: they make a subclass of vtkPlot which has a vtkImageData as a private Texture variable, and then paints the texture within the plot's bounds. This way they can instantiate a vtkChartXY and use AddPlot() to add what is basically an image painter, and then vtkChartXY takes care of the axes internally. Just an idea that I've seen the developers using.

Anyway, hopefully Marcus or someone else will be able to take a look at this sometime soon, but I know he's very busy right now.

Talk to you later,
-Eric

# =======
import vtk

view = vtk.vtkContextView()
view.GetRenderWindow().SetSize(400, 300)

axis1 = vtk.vtkAxis()
axis1.SetPoint1(75,75)
axis1.SetPoint2(75,225)
axis1.SetPosition(vtk.vtkAxis.LEFT)
axis1.SetTitle('YAxis')
axis1.Update()
view.GetScene().AddItem(axis1)

axis2 = vtk.vtkAxis()
axis2.SetPoint1(75,75)
axis2.SetPoint2(325,75)
axis2.SetPosition(vtk.vtkAxis.BOTTOM)
axis2.SetTitle('XAxis')
axis2.Update()
view.GetScene().AddItem(axis2)

view.Render()
view.GetInteractor().Start()
# =======


On Dec 7, 2010, at 10:46 AM, Frese Daniel Dr. wrote:

> Hi Eric,
>  
> here it is, or at least the relevant part.
> I’m sorry it’s a bit lengthy, even though I omitted some stuff around. I did this
> in the Visual Studio and created a WinForms control (which by the way worked nicely),
> so “this” points to an instance of the form in order to get the dimensions of the output window.
> The double locdata array and the dimensions of the image etc. are stored in private elements of the
> WinForm control.
>  
> This is basically my first effort with these routines in order to try out things,
> so I wouldn’t be surprised if things can be done in a better way. I put the axes
> in a different scene in order to work around some strange things when using vtk 5.6.1,
> but now I am using the latest git stuff (or nearly, I downloaded yesterday afternoon)
> and there is no need any more for any workarounds (vtk & life has become better J).
> Placing the axes into the view’s scene does not change their behavior however (I tested).
>  
> Thank you very much for your interest in this !
> Daniel
>  
>  
>       void vtk2dDataControl::VTKRender() {
>             double *minmax;                          // min and max within the data
>             int nColors = 1000;                      // number of colors
>             double colorposition[2];           // holds the position of the colorbar
>             int windowsizeX;                   // X window size - to be supplied externally
>             int windowsizeY;                   // Y window size - to be supplied externally
>             int imageextent[6];                      // extent of the imgage
>             int barwidth = 120;                      // FIXME, X space for colorbar
>             int labelnum;                            // number of labels - a helper var
>             int upperborder = 20;              // border space between upper image edge and window edge
>             int rightborder = 40;              // space between image and colorbar
>             int i;
>  
>  
>             // calculate the effective width of the window, that can be used for the display
>             windowsizeX = this->Width;
>             windowsizeY = this->Height;
>             effectiveSizeX = windowsizeX  - imageposition[0] - barwidth - rightborder;
>             effectiveSizeY = windowsizeY  - imageposition[1] - upperborder;
>            
>             // import the data into the vtkimagedata structure
>             VTK_CREATE(vtkImageImport, import);
>             import->SetImportVoidPointer(localdata);
>             import->SetDataScalarTypeToDouble();
>             import->SetWholeExtent(0,locdimX-1,0,locdimY-1,0,0);
>             import->SetDataExtent(0,locdimX-1,0,locdimY-1,0,0);
>             import->Update(); // call update for getting the right minmax values below...
>             minmax = import->GetOutput()->GetScalarRange();
>  
>             // resample the image in order to fit into the given window geometry
>             VTK_CREATE(vtkImageResample, resample);
>             resample->SetInputConnection(import->GetOutputPort());
>             resample->SetDimensionality(2);
>             resample->SetAxisMagnificationFactor(0, ((double) effectiveSizeX) / locdimX);
>             resample->SetAxisMagnificationFactor(1, ((double) effectiveSizeY) / locdimY);
>  
>             // add a colorbar
>             VTK_CREATE(vtkLookupTable, lookupTable);
>             VTK_CREATE(vtkScalarBarActor, colorbar);
>             lookupTable->SetNumberOfColors(nColors);
>             lookupTable->SetTableRange(minmax);
>             //lookupTable->SetSaturationRange(0, 1);
>             //lookupTable->SetHueRange(0, 1);
>             lookupTable->SetRampToLinear();
>             lookupTable->Build();
>  
>             // Filter to convert the grey image into an RGB output
>             VTK_CREATE(vtkImageMapToColors, rgb);
>             rgb->SetInputConnection(resample->GetOutputPort());
>             rgb->SetLookupTable(lookupTable);
>             rgb->SetOutputFormatToRGBA();
>             rgb->Update();
>  
>             // Set up a 2D context view - this is the basic 2D API structure
>             if (view != NULL) view->Delete();
>             view = vtkContextView::New();
>             view->GetRenderWindow()->SetSize(windowsizeX, windowsizeY); 
>  
>             // register the image into the view and position it
>             VTK_CREATE(vtkImageItem, item); 
>             view->GetScene()->AddItem(item);
>             item->SetImage(vtkImageData::SafeDownCast(rgb->GetOutput()));
>             item->GetImage()->GetExtent(imageextent);
>             item->SetPosition(imageposition[0], imageposition[1]);
>  
>             // create a new scene for axes and colorbar; also create actor for axes
>             VTK_CREATE(vtkContextScene, axesscene);
>             VTK_CREATE(vtkContextActor, axesactor);
>  
>             // Starting from here there is mainly stuff for the axes...
>             // X Axis
>             VTK_CREATE(vtkAxis, Xaxis);
>             Xaxis->SetBehavior(1); // rescalable
>             // now define location of axis by giving two points
>             Xaxis->SetPoint1(imageposition[0], imageposition[1]);
>             Xaxis->SetPoint2((int) imageextent[1]-imageextent[0] + imageposition[0], imageposition[1]);
>             Xaxis->SetPosition(vtkAxis::BOTTOM);     // this is an axis at the bottom
>             Xaxis->SetTitle(XAxisName->c_str());     // title of axis
>             Xaxis->GetPen()->SetWidth(2);            // lines are 2 pixel wide
>             Xaxis->SetMinimum(locXmin);                    // set Xmin and ...
>             Xaxis->SetMaximum(locXmax);                    // ... Xmax for later autoscale()
>             Xaxis->SetPrecision(2);                        // two figures after period
>             Xaxis->SetNotation(2);                         // "mixed" (i.e. standard or scientific)
>             Xaxis->AutoScale();                                  // perform autoscale for ticks
>             Xaxis->Update();                               // do it !
>             Xaxis->SetMinimum(locXmin);                    // got to reste min/max values afetr autoscale
>             Xaxis->SetMaximum(locXmax);
>             Xaxis->GetGridPen()->SetColor(0,0,0,1); // write in black
>             Xaxis->SetLabelsVisible(true);                 // show it all...
>             Xaxis->SetVisible(true);
>             //Xaxis->GetTitleProperties()->SetLineOffset(10);
>             Xaxis->Update();                               // do it !
>             axesscene->AddItem(Xaxis);                     // add to scene
>  
>             // Y Axis
>             // everything completely analogous to X Axis - so no need for comments here
>             VTK_CREATE(vtkAxis, Yaxis);
>             Yaxis->SetBehavior(1);
>             Yaxis->SetPoint1(imageposition[0], imageposition[1]);
>             Yaxis->SetPoint2(imageposition[0], (int) imageextent[3]-imageextent[2] + imageposition[1]);
>             Yaxis->SetPosition(vtkAxis::LEFT);
>             Yaxis->SetTitle(YAxisName->c_str());
>             Yaxis->GetPen()->SetWidth(2);
>             Yaxis->SetMinimum(locYmin);
>             Yaxis->SetMaximum(locYmax);
>             Yaxis->AutoScale();
>             Yaxis->Update();
>             Yaxis->SetMinimum(locYmin);
>             Yaxis->SetMaximum(locYmax);
>             Yaxis->GetGridPen()->SetColor(0,0,0,1);
>             Yaxis->GetTitleProperties()->SetOrientation(90.0);
>             Yaxis->SetLabelsVisible(true);
>             Yaxis->SetVisible(true);
>             Yaxis->Update();
>             axesscene->AddItem(Yaxis);
>  
>             // prepare axes on top and on right w/o labels (just ticks)
>             labelnum = Xaxis->GetTickPositions()->GetDataSize();
>             VTK_CREATE(vtkStringArray, Xemptylabels);
>             Xemptylabels->SetNumberOfValues(labelnum);
>             for (i=0; i<labelnum; i++) {
>                   Xemptylabels->SetValue(i, "");
>             }
>             labelnum = Yaxis->GetTickPositions()->GetDataSize();
>             VTK_CREATE(vtkStringArray, Yemptylabels);
>             Yemptylabels->SetNumberOfValues(labelnum);
>             for (i=0; i<labelnum; i++) {
>                   Yemptylabels->SetValue(i, "");
>             }
>  
>             // create axis on top of image
>             VTK_CREATE(vtkAxis, XaxisUpper);
>             XaxisUpper->SetBehavior(1);
>             XaxisUpper->SetPoint1(imageposition[0], imageposition[1] + (int) (imageextent[3]-imageextent[2]));
>             XaxisUpper->SetPoint2((int) imageextent[1]-imageextent[0] + imageposition[0], imageposition[1] + (int) (imageextent[3]-imageextent[2]));
>             XaxisUpper->SetPosition(vtkAxis::TOP);
>             XaxisUpper->GetPen()->SetWidth(2);
>             XaxisUpper->SetMinimum(locXmin);
>             XaxisUpper->SetMaximum(locXmax);
>             // want to have same number of ticks as X axis ...
>             XaxisUpper->SetNumberOfTicks(Xaxis->GetTickPositions()->GetDataSize());
>             XaxisUpper->GetGridPen()->SetColor(0,0,0,1);
>             // ... and same positions of ticks as X axis ...
>             XaxisUpper->SetTickPositions(Xaxis->GetTickPositions());
>             // .. but no labels this time.
>             XaxisUpper->SetTickLabels(Xemptylabels);
>             XaxisUpper->SetVisible(true);
>             XaxisUpper->Update();
>             axesscene->AddItem(XaxisUpper);
>  
>             // create axis on the right of top image - analogous to XaxisUpper above
>             VTK_CREATE(vtkAxis, YaxisRight);
>             YaxisRight->SetBehavior(1);
>             YaxisRight->SetPoint1(imageposition[0] + (int) imageextent[1]-imageextent[0], imageposition[1]);
>             YaxisRight->SetPoint2(imageposition[0] + (int) imageextent[1]-imageextent[0], (int) imageextent[3]-imageextent[2] + imageposition[1]);
>             YaxisRight->SetPosition(vtkAxis::RIGHT);
>             YaxisRight->GetPen()->SetWidth(2);
>             YaxisRight->SetMinimum(locYmin);
>             YaxisRight->SetMaximum(locYmax);
>             YaxisRight->SetNumberOfTicks(Yaxis->GetTickPositions()->GetDataSize());
>             YaxisRight->GetGridPen()->SetColor(0,0,0,1);
>             YaxisRight->SetTickPositions(Yaxis->GetTickPositions());
>             YaxisRight->SetTickLabels(Yemptylabels);
>             YaxisRight->SetVisible(true);
>             YaxisRight->Update();
>             axesscene->AddItem(YaxisRight);
>  
>             // now format and position colorbar
>             colorbar->SetLookupTable(lookupTable);
>             colorposition[0] = 1.0 - (1.0* barwidth)/windowsizeX;
>             colorposition[1] = (1.0* imageposition[1])/windowsizeY;
>             colorbar->SetWidth(0.5);
>             colorbar->SetHeight(1.0 - 2* colorposition[1]);
>             colorbar->SetPosition(colorposition);
>             colorbar->SetLabelFormat("%1.2E");
>             colorbar->PickableOff();
>             colorbar->SetMaximumWidthInPixels(barwidth);
>             colorbar->VisibilityOn();
>             colorbar->GetLabelTextProperty()->SetShadow(0);
>             colorbar->GetLabelTextProperty()->SetColor(0,0,0);
>  
>             // register the axescene to the axesactor, which and point to the renderer
>             axesactor->SetScene(axesscene);
>             view->GetRenderer()->AddActor(axesactor);
>  
>             // register the colorbar as an actor
>             view->GetRenderer()->AddActor(colorbar);
>  
>             RenderWindow = view->GetRenderWindow();
>             RenderWindow->SetWindowId((HWND)Handle.ToInt64());
>  
>             // set Interactor Style to RubberBand
>             VTK_CREATE(vtkInteractorStyleRubberBand2D, RubberBandStyle);
>             RubberBandStyle->SetRenderOnMouseMove(false);
>             VTK_CREATE(vtkCallbackCommand, SelectionChangedCallback);
>             SelectionChangedCallback->SetCallback(SelectionChangedCallbackFunction);
>             RubberBandStyle->AddObserver(vtkCommand::SelectionChangedEvent,SelectionChangedCallback);
>             RenderWindow->SetInteractor(WinInteractor);
>             RenderWindow->SetDoubleBuffer(1);
>             WinInteractor->SetInteractorStyle(RubberBandStyle);
>             WinInteractor->Initialize();
>       }
>  
> Von: Eric E. Monson [mailto:emonson at cs.duke.edu] 
> Gesendet: Dienstag, 7. Dezember 2010 16:13
> An: Frese Daniel Dr.
> Cc: Marcus D. Hanwell; vtkusers at vtk.org
> Betreff: Re: AW: [vtkusers] Positioning titles within vtkAxis
>  
> Hey Daniel,
>  
> Yes, this shouldn't be happening. Would you be able to send the section of your code that generates this chart? I'm curious how you're implementing the combination of ImageItem and axes. Maybe there is another way of accomplishing the same thing that wouldn't cause the overlap, or it might at least help us diagnose why the label placement routine isn't dealing with your case correctly.
>  
> Also, just to be clear, was this generated with the current development (git) version, or with 5.6.1?
>  
> Thanks,
> -Eric
>  
>  
> On Dec 7, 2010, at 8:29 AM, Frese Daniel Dr. wrote:
> 
> 
> Hello Eric, Marcus,
>  
> before I explain my problem once more I just want to add that I find the charts functionality already quite useful.
> As I said I just updated my vtk stuff and I can imagine it must have been quite some work to get to this point.
>  
> I appended a screenshot illustrating the problem. Since I don’t know how this appears on the mail list I just describe briefly.
> I have a scene with a vtkImageItem to show some 2D matrix data. Around the image I have axes (vtkAxis objects) with
> appropriate ticks, tick labels and axes titles. The problem is that the axes titles overlap with the tick labels. E.g. for the
> case of the X axis , the title should be lower such that it does not touch the labels, but there does not seem to
> be a way to do that as of now.
>  
> A possible low level solution would be a way to specify some vertical (horizontal axis case) or some horizontal (vertical axis case) offset
> for the position of the titles (in pixel or font size units).
> In principle of course the vtkAxis object could calculate such an offset by itself, since it has access to both
> the labels’ and the titles’ text properties.
>  
> What do you think ?
> Daniel
>  
> Von: Eric E. Monson [mailto:emonson at cs.duke.edu] 
> Gesendet: Dienstag, 7. Dezember 2010 13:54
> An: Frese Daniel Dr.
> Cc: vtkusers at vtk.org
> Betreff: Re: [vtkusers] Positioning titles within vtkAxis
>  
> Hey Daniel,
>  
> It does seem like SetLineOffset should do something like what you want, but I think they way the label text is applied with VerticalJustification probably nullifies any line offset setting. Line spacing shouldn't matter for a single line of text.
>  
> So, the adjustments you want are just not implemented. Marcus, the developer, has worked hard to get the labels right, though, so if you have a use case where the labels are running into the axis ticks maybe you should describe the situation and send a screen shot – it may be something that needs fixing. 
>  
> You're right that the charts are still under development, but some of the core functionality has settled down, and as you said, the current implementation is better than the 5.6.1 version.
>  
> -Eric
>  
> ------------------------------------------------------
> Eric E Monson
> Duke Visualization Technology Group
> 
> 
>  
>  
> On Dec 7, 2010, at 3:35 AM, Frese Daniel Dr. wrote:
> 
> 
> 
> Hi all,
>  
> I have a problem positioning an axis title relative to its vtkAxis object.
> Basically, if I draw a horizontal  X-axis, the assigned title is written such that it overlapps with the
> tick labels. Reading through the docs, I got the impression that I should be able to introduce a
> vertical offset between the drawn axis and the titel by using either a call to
> Xaxis->GetTitleProperties()->SetLineOffset(offset_in_pixel)
> or by 
> Xaxis->GetTitleProperties()->SetLineSpacing(scale_factor).
> But neither call seems to have any effect.
> Moving from 5.6.1 to the latest vtk git source tree I noticed that the chart stuff seems to have
> improved greatly (most functions a joy to use !), but it still seems to be a work in progress.
> So am doing something stupid and do I miss something here or is this feature just not
> implemented yet ?
>  
> Daniel
>  
> </PRE><p>
> ------------------------------------------------------------------------------------------------------ <br>
> Registergericht: Traunstein / Registry Court: HRB 275 - Sitz / Head Office: Traunreut <br>
> Aufsichtsratsvorsitzender / Chairman of Supervisory Board: Rainer Burkhard <br>
> Geschäftsführung / Management Board: Thomas Sesselmann (Vorsitzender / Chairman),<br>
> Michael Grimm, Matthias Fauser, Sebastian Tondorf<br><br>
> <a href="http://www.heidenhain.de/disclaimer" target="_blank">E-Mail Haftungsausschluss / E-Mail Disclaimer</a><br><pre>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.vtk.org/pipermail/vtkusers/attachments/20101207/568ddbce/attachment.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: AxisLabelOverlap.png
Type: image/png
Size: 16550 bytes
Desc: not available
URL: <http://www.vtk.org/pipermail/vtkusers/attachments/20101207/568ddbce/attachment.png>


More information about the vtkusers mailing list