How can I add some text on top of a bar in a chart.
This is the code I have to add the bar:
var color = ColorTranslator.FromHtml(row.Colour);
var barItem = graphPane.AddBar(row.Propensity.ToString(), null, Ys.ToArray(), color);
Thank you
Here is a quick example using TextObj to simply add labels to each bar.
GraphPane myPane = zedGraphControl1.GraphPane;
double[] y = { 100, 50, 75, 125 };
BarItem myBar = myPane.AddBar("Data", null, y, Color.Red);
for (int i = 0; i < myBar.Points.Count; i++)
{
TextObj barLabel = new TextObj(myBar.Points[i].Y.ToString(), myBar.Points[i].X, myBar.Points[i].Y + 5);
barLabel.FontSpec.Border.IsVisible = false;
myPane.GraphObjList.Add(barLabel);
}
myBar.Label.IsVisible = true;
zedGraphControl1.AxisChange();
zedGraphControl1.Invalidate();
Of course this just uses the value of the data as the label. If you wanted to use custom labels, you could create a string array or list and use that inside the loop.
Here are some ZedGraph references:
Introduction and examples: http://www.codeproject.com/KB/graphics/zedgraph.aspx
Source code documentation: http://zedgraph.sourceforge.net/documentation/default.html
You need to define AlignH and AlignV in your text object:
TextObj textLabel = new TextObj(value.ToString(), positionX, value, CoordType.AxisXYScale, AlignH.Center, AlignV.Top);
AlignV define the position of your value on the bar.
Providing you want the label text to match the value of each bar, then you can do it with a single line of code:
BarItem.CreateBarLabels(graphPane, false, "F0");
Note that the 3rd parameter is a double.ToString format. e.g. "F0" = 12, "F2" = 12.34
However, if you want any flexibity with it then this solution is not ideal. It also doesn't work very well if you have a stacked bar chart, because having any 0 value data will cause labels to overlap and look horrific
Related
I use C# and Oxyplot.
I have a LineAnnotation to which I want to add a text.
So I have set Text Property for the LineAnnotation, but the text is vertical aligned.
How could I add a text (1..3 lines) to a LineAnnotation and that texts shows horizontally, so that users can read it ?
Not good :
What I would like:
LineAnnotation Markerline = new LineAnnotation();
Markerline.Color = OxyColors.Blue;
Markerline.LineStyle = LineStyle.Solid;
Markerline.StrokeThickness = 5;
Markerline.Type = LineAnnotationType.Vertical;
Markerline.XAxisKey = "x1";
Markerline.YAxisKey = yAxisKey;
Markerline.Tag = "Marker";
Markerline.Text = "Hello World"; //how to display on top of Markerline horizontally ?
Just set the LineAnnotationType:
Markerline.Type = LineAnnotationType.Horizontal;
You need to LineAnnotation.TextOrientation property. For example,
Markerline.TextOrientation = AnnotationTextOrientation.Horizontal;
In addition, you could also set the LineAnnotation.TextHorizontalAlingment Property to dictate on the position of Text with respect to the Line Annotation.
Markerline.TextHorizontalAlignment = HorizontalAlignment.Left;
I'm encountering a problem about resizing the column based on the cell that has the longest content. In the following example, I want all cell's width re-adjust according to the length of the content in "ADDRESS" column. Please help, and thank you in advance.
public void setPnLTable(int x, int y){
String[] ColNames = {"Name", "AGE", "ADDRESS"};
private String [][] getData(){t[0][0] = "John Smith"; t[0][1] = "55"; t[0][2] = "1600 Pennsylvania Ave NW, Washington, DC 20500";
DefaultTableModel tm = new DefaultTableModel(getData(),ColNames);
//
jPnLTABLE = new JTable(tm);
// Center Columns
cr.setHorizontalAlignment( JLabel.CENTER );
for (int i = 0; i < ColNames.length; i++){
jPnLTABLE.getColumnModel().getColumn(i).setCellRenderer(cr);
}
jPnLTABLE.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
JScrollPane js = new JScrollPane(jPnLTABLE);
//
js.setBounds(x, y, 2000, 500); // IT'S HARD-CODED;
//CAN I RESIZE IT BASED ON THE LENGTH OF THE CELL CONTENT
jPnLTABLE.getTableHeader().setReorderingAllowed(false);
jPnLTABLE.getTableHeader().setFont(new Font(null, Font.BOLD, 12));
add(js);
}
If you make your JFrame a BorderLayout and put your JScrollPane BorderLayout.CENTER no need at all to set the size of the JSrollPane it will take all the available space
If your JScrollPane is inside a cell of a GridLayout no problem neither it will re-ajust no need to set its size
Allways easier to put the JScrollPane inside a JPanel (GridLayout(1,1) or BorderLayout.CENTER) and let the Layout manager to do the adjustement on the JPanel.
or maybe you can use
table.setFillsViewportHeight( true );
I have a stacked column report and i need to show the label value inside each of the series, is this possible. here is the code i have so far. It does look like barcharts have this option, not sure if i need to convert report to that type.
chart.Title.Text = "Total Pipeline - Initiative Count by Release";
chart.Title.Font.Size = 8;
chart.SetPosition(45, 0, 3, 0);
chart.SetSize(400, 300);
chart.Legend.Add();
chart.YAxis.MajorUnit = 10;
var series1 = chart.Series.Add(Chartsheet.Cells["L23:Q23"], Chartsheet.Cells["L22:Q22"]);
series1.HeaderAddress = new ExcelAddress("'Graphs'!K23");
var series2 = chart.Series.Add(Chartsheet.Cells["L24:Q24"], Chartsheet.Cells["L22:Q22"]);
series2.HeaderAddress = new ExcelAddress("'Graphs'!K24");
chart.Legend.Position = eLegendPosition.Bottom;
chart.YAxis.LabelPosition = eTickLabelPosition.NextTo;
chart.XAxis.MajorTickMark = eAxisTickMark.Out;
chart.XAxis.MinorTickMark = eAxisTickMark.None;
chart.ShowDataLabelsOverMaximum = true;
so i just forced a format of a barchart and i have the label option
var chart = (OfficeOpenXml.Drawing.Chart.ExcelBarChart) Chartsheet.Drawings.AddChart("chart", eChartType.ColumnStacked);
After I set a column's WrapText=true, I want to see what the new height of the row will be (i.e. if the text wraps, for how many lines). It appears that the Height property of a row is not updated.
ExcelPackage pkg = new ExcelPackage();
ExcelWorksheet sheet = pkg.Workbook.Worksheets.Add("Test");
// height is 15.0
double heightBefore = sheet.Row(1).Height;
sheet.Cells[1, 1].Value = "Now is the time for all good men to come to the aid of their country";
ExcelColumn col = sheet.Column(1);
// this will resize the width to 60
col.AutoFit();
if (col.Width > 50)
{
col.Width = 50;
// this is just a style property, and doesn't actually execute any recalculations
col.Style.WrapText = true;
}
// so this is still 15.0. How do I get it to compute what the size will be?
double heightAfter = sheet.Row(1).Height;
// open the xls, and the height is 30.0
pkg.SaveAs(new System.IO.FileInfo("text.xlsx"));
In fact, a search for the Height property (or the underlying field _height) shows that it is only set by the property setter, and does not ever seem to be set based on anything else (like content in the row).
Any ideas on how I can get a refreshed Height for a row?
Thanks
The general pattern I've noticed with EPPlus is that it generates the framework of the document with the minimum amount of information necessary. Then, when you open the file, Excel fills out the remaining XML structure, which is why you always have to save the file after opening an EPPlus generated document.
For your question, I'm assuming that Excel is updating the row heights after you open the Excel file so EPPlus would not have the updated row height information. I'm not absolutely certain that the library doesn't support this, but like you I was unable to find a way to get the updated values.
One workaround however could be to just calculate what the value would be since you know your text length and column width:
ExcelPackage pkg = new ExcelPackage();
ExcelWorksheet sheet = pkg.Workbook.Worksheets.Add("Test");
// height is 15.0
double heightBefore = sheet.Row(1).Height;
var someText = "Now is the time for all good men to come to the aid of their country. Typewriters were once ground-breaking machines.";
sheet.Cells[1, 1].Value = someText;
ExcelColumn col = sheet.Column(1);
ExcelRow row = sheet.Row(1);
// this will resize the width to 60
col.AutoFit();
if (col.Width > 50)
{
col.Width = 50;
// this is just a style property, and doesn't actually execute any recalculations
col.Style.WrapText = true;
}
// calculate the approximate row height and set the value;
var lineCount = GetLineCount(someText, (int)col.Width);
row.Height = heightBefore * lineCount;
// open the xls, and the height is 45.0
pkg.SaveAs(new System.IO.FileInfo("text.xlsx"));
Here's the method to calculate the number of lines:
private int GetLineCount(String text, int columnWidth)
{
var lineCount = 1;
var textPosition = 0;
while (textPosition <= text.Length)
{
textPosition = Math.Min(textPosition + columnWidth, text.Length);
if (textPosition == text.Length)
break;
if (text[textPosition - 1] == ' ' || text[textPosition] == ' ')
{
lineCount++;
textPosition++;
}
else
{
textPosition = text.LastIndexOf(' ', textPosition) + 1;
var nextSpaceIndex = text.IndexOf(' ', textPosition);
if (nextSpaceIndex - textPosition >= columnWidth)
{
lineCount += (nextSpaceIndex - textPosition) / columnWidth;
textPosition = textPosition + columnWidth;
}
else
lineCount++;
}
}
return lineCount;
}
One thing to keep in mind is that Excel has a max row height of 409.5 so you'll want to make sure your column width is not so narrow that you'll reach this limit.
Also, another thing I noticed is that the column widths that you manually set with EPPlus don't actually set the columns to the expected value. For example, if you set your column width to 50, you'll notice that the actual column width is set to 49.29 so you may want to factor that in as well.
In Adobe Edge Animate, how do I get the name of the label that corresponds to a given time? I've seen that I can get the current time as an integer using
sym.getPosition()
but if there's a label at that position, how do I get the label as a string?
function getLabel() {
var stage = sym.getComposition().getStage();
var labels = stage.timelines['Default Timeline'].labels;
var currentLabel;
var currentPosition = stage.getPosition();
$.each( labels, function( label, position ){
if (position <= currentPosition) currentLabel = label;
});
return currentLabel;
}
console.log( getLabel() );
this will return the label on (or next previous to) the current position.
For those of us here looking for a Adobe Animate 2019 solution (like I was), it's similar, but slightly different:
function getLabel(_this) {
var currentLabel;
var currentPosition = _this.currentFrame;
_this.labels.forEach(function( label, index ){
if (label.position <= currentPosition) currentLabel = label.label;
});
return currentLabel;
}
Your position on the timeline is easier to get, and the labels object is organized differently. (Also jQuery is unavailable.)