I'm displaying cities (US) and set it up so that labels (citi names) don't overlap. This causes some of them to be suppressed. I'm fine with that. What I'd like to do is arbitrate which labels to be suppressed. Such as, if the algorithm has to suppress a label, it better drop the one from the citi whose population is smaller. Is this possible?
Arbitrate between labels when LabelOverlappingRule.NoOverlapping is used
Hi Adrian,
The current Web Edition doesn’t support to suppress some label by a specific column’s data directly. But I think you could implement this by writing a CusomTextStyle which is derived from TextStyle, and overriding the DrawCore function. The code could be as following:
protected override void DrawCore(IEnumerable<Feature> features, GeoCanvas canvas, Collection<SimpleCandidate> labelsInThisLayer, Collection<SimpleCandidate> labelsInAllLayers)
{
Collection<Feature> candidateFeatures = FilterFeatures(features, canvas);
Dictionary<Feature, Collection<LabelingCandidate>> allLabels = new Dictionary<Feature,Collection<LabelingCandidate>>();
foreach (Feature feature in candidateFeatures)
{
Collection<LabelingCandidate> labelingCandidates = GetLabelingCandidates(feature, canvas);
allLabels.Add(feature, labelingCandidates);
}
// Check if each label in allLebels dictionary overlapping each other, and compare the population of the overlapping
// features. Then remove the feature which you don't need. At last call the base.Draw function with the processed features.
// You may need the method CheckOverlapping in this class.
}
You could test against your data when you finish this implementation. Please feel free to let me know if you have more questions about this.
Thanks,
Sun
Thank you, Sun. Your advice put me on the right track. What I noticed is that it would suffice if I added the features to the layer in the priority order. However, for some layers I don’t control the _order_ of features, so the custom TextStyle is still necessary. In there I just sort the candidateFeatures based on their priority. And it works. Thanx.
PS. after sorting I call the base.DrawCore, not base.Draw method which leads to endless recursion, stack overflow.
That’s great to hear that you have found the right way to implement this, and sorry for my mistake about the base.Draw method, the base.DrawCore method is really need to be called instead.
Any more questions please let me know.
Thanks,
Sun
Resurrecting this after a long while. It turns out that placing the features in sorted order is (no longer) enough. For some reason the wrong labels are suppressed. I’v also tried to implement the suggestion from 10/19/2009, but the performance is disastrous. Given features in the thousands for each tile, it takes so long to do the filtering in DrawCore that the engine gives up on several tiles (pink empty results). Maybe I didn’t figure it out the correct way of implementing this. Could you (Sun?) elaborate on the implementation you suggested on 10/19 and test it for performance on a cities shp?
Ideally, ranking labels based on a field, should be a feature of the engine, where the suppressing of labels already takes place and where I would think a most efficient implementation would be possible.
Adrian,
What version you are using? If you are using the latest 4.5 one, we now have the overlap property to control the Overlapping. The codes can be like this.
ShapeFileFeatureLayer majorCitiesShapeLayer = new ShapeFileFeatureLayer(Server.MapPath(@"~\SampleData\USA\cities_a.shp"));
majorCitiesShapeLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.City3;
majorCitiesShapeLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = TextStyles.City3("AREANAME");
majorCitiesShapeLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle.BestPlacement = true;
majorCitiesShapeLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle.OverlappingRule = LabelOverlappingRule.NoOverlapping;
majorCitiesShapeLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
majorCitiesShapeLayer.DrawingMarginPercentage = 50;
Please let us know if you have any issues.
Thanks,
James
James, my problem is not that labels overlap. I know that I can set the OverlappingRule property to NoOverlapping. My problem is that when NoOverlapping is set, the choice of which label to suppress (in cases of overlap) is not done based on a rank order defined in another field (Column value in Feature), but somewhat random. All my efforts are to implement such a ranking that is missing from the engine.
I am using WebEditionFull4.0.40.0 and the OverlappingRule is present there too.
I’ve traced the problem to suppressing partial labels. Turns out for a surprising large number of big cities, their labels span across tile boundaries and are therefore suppressed. Alas, this is not acceptable. I need a way to _not_ suppress partial labels, and yet to be able to have them match seamlessly at tiles boundaries. This matching doesn’t happen.
Adrian,
We are working on the sample application for your requirements, we will give you a result tomorrow for your two issues,
Thanks,
Scott,
For this problem I have opened a ticket 3357
helpdesk.thinkgeo.com/TicketEdit?ticketId=27692d1e-822e-4305-b275-d7029566d1f6
In there I’ve added pictures highlighting the problems I’m seeing. If needed I’d send you the code I’m using (a sample standalone sample app).
Adrian,
If you can send us your sample application it is real useful for us, we are making the sample application by ourselves and we cannot find out any performance issues, please send the application with data to support@thinkgeo.com,
Thanks,
Scott,
Adrian,
I would like to also bring an other potential solution although this is a pretty heavy one.
Suppressing label is based on the order they are in the shapefile. A solution could be to create a new shapefile with the features ordered by population from highest to lowest. This is a one time operation but after the shapefile is created you don't have to worry about using some custom TextStyle with performance impact. The labeling order is built in the shapefile itself. In a way, this is a type of geoprocessing operation where a new layer is created based on an original one. And you can find some examples of how to create a new layer in the section "Spatial Functions" of the Code Community wiki.thinkgeo.com/wiki/Map_Suite_We...ns_Samples
This might be a solution that does not fit your requierements but I wanted to bring that up.
Val.
I am sorting the features, not in the shapefile, but in a customized TextStyle (ArbitratingTextStyle derived from TextStyle), just like Sun suggested in his post on this tread from 10-19-2009. This works, and there are no performance issues with it.
In addition what I tried was to eliminate features based on label overlapping; this stage is what took a performance hit. As I discovered later, such a process is not necessary, the native engine does it fast and quite well anyway. The problem I have traced it to suppressing partial labels. Turns out I can’t afford to suppress partial labels (because important labels don’t show up in such case), but if I don’t, then there are issues with matching at tile boundaries. I need a way to insure perfect matching of labels at tile boundaries, without suppressing partial labels.
Will send you my app as indicated at support@thinkgeo.com
Adrian,
It sounds like the best idea to receive your sample app from you to find the most appropriate solution for your case. Let us know when you have the app sent at support@thinkgeo.com. Thank you.
I have sent the sample app (RankingLabels.zip) as you indicated. I've also attached it to the Ticket I've opened,
helpdesk.thinkgeo.com/Ticket...029566d1f6
A.
Adrian,
Ok. We received it. Scott or I will let you know our findings on that early next week. Thank you.
Adrian,
We have received your sample application and changed the sample code for your requirement, please check the detailed information from the ticket,
Thanks,
Scott,