mpAndroidChart: Xaxis.setPosition to Bottom_Inside not working on HorizontalBarChart - mpandroidchart

I have a HorizontalBarChart with mpAndroidChart and I am having problems to display the labels on the left side, but within the graph. It looks like this:
the labels are chopped of on the left side. This is done via the line
testchart.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM_INSIDE)
On the right side, it works smoothly:
The labels are inside the graph and fully displayed. This is done by the line:
testchart.getXAxis().setPosition(XAxis.XAxisPosition.TOP_INSIDE)
Any idea what I am doing wrong?
My Code for the chart is:
BarData data = new BarData(new BarDataSet(entries, "Labeltest"));
data.setBarWidth(1); // set custom bar width
data.setDrawValues(false);
oBinding.testchart.setData(data);
oBinding.testchart.getXAxis().setLabelCount(labels.size());
oBinding.testchart.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM_INSIDE);
oBinding.testchart.getXAxis().setValueFormatter(new IndexAxisValueFormatter(labels));
// Hide grid lines
oBinding.testchart.getAxisLeft().setEnabled(false);
oBinding.testchart.getAxisRight().setEnabled(false);
// Hide graph description
oBinding.testchart.getDescription().setEnabled(false);
// Hide graph legend
oBinding.testchart.getLegend().setEnabled(false);
oBinding.testchart.invalidate(); // refresh
and in XML:
<com.github.mikephil.charting.charts.HorizontalBarChart
android:id="#+id/testchart"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

I have encountered the same problem, I solved it this way.
chart.getXAxis().setPosition(XAxisPosition.BOTTOM_INSIDE)
In that way the labels should be drawn over the bars. You can further reposition the labels by using the setXOffset(...) and setYOffset(...) methods of the XAxis class.
If you have a better way, please let me know, thank you

Try this:
XAxis xAxis = chart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM_INSIDE);
Added in response to comment from #andreas-zuercher:
This way has always worked for me. This also makes it easy to set other axis parameters like:
xAxis.setDrawGridLines(true);
xAxis.setGranularity(1f);
xAxis.setGranularityEnabled(true);
final String[] xTime = time.split(",");
xAxis.setValueFormatter(new IAxisValueFormatter() {
#Override
public String getFormattedValue(float value, AxisBase axis) {
return xTime[(int) value-1];
}
});
xAxis.setValueFormatter(new IndexAxisValueFormatter(xTime));

Related

Custom CollapsingTopAppBar Jetpack Compose

The essence of the problem is that I want to write my own version of the AppBar that would include content as another Compose function. After looking at the source code of the current CollapsingTopAppBar implementation, I saw the following lines:
#Composable
private fun TwoRowsTopAppBar(
...
scrollBehavior: TopAppBarScrollBehavior?
) {
...
val pinnedHeightPx: Float = 64.dp
val maxHeightPx: Float = 152.dp
LocalDensity.current.run {
pinnedHeightPx = pinnedHeight.toPx()
maxHeightPx = maxHeight.toPx()
}
// Sets the app bar's height offset limit to hide just the bottom title area and keep top title
// visible when collapsed.
SideEffect {
if (scrollBehavior?.state?.heightOffsetLimit != pinnedHeightPx - maxHeightPx) {
scrollBehavior?.state?.heightOffsetLimit = pinnedHeightPx - maxHeightPx
}
}
...
Surface(...) {
Column {
TopAppBarLayout(
...
heightPx = pinnedHeightPx
...
)
TopAppBarLayout(
...
heightPx = maxHeightPx - pinnedHeightPx + (scrollBehavior?.state?.heightOffset
?: 0f),
...
)
}
}
}
As I understand it, scrollBehavior is used to handle the collapse and expansion behavior. In the current implementation, just constant values are put in heightOffsetLimit. And since I need my appbar implementation to be able to contain content of any size, I need to somehow know the size of this content in advance and put this value in heightOffsetLimit.
I have already written the code for my AppBar, so that it also contains content. But since I can't pass the height value of the content to scrollBehavior, the AppBar doesn't collapse to the end.
you need to calculate the height that the appbar will have before drawing it into the screen. I have followed this issue and solved my problem with the last solution. hope it helps:
Get height of element Jetpack Compose
use the content you can put (ex. an image or a huge text) as the MainContent
use your appbar as the DependentContent and use the size given in lambda to give the height to your appbar
finally set placeMainContent false as I believe you don't need to draw the image (or any other composable) directly in a box
and you will good to go

Wrap or cut long labels in Pentaho CCC

How to cut long labels of the Bar Chart Control’s base axis?
I have already tried to cut them in the Extension Points (baseAxisLabel_text):
function(a){
var str=this.scene.atoms.category.label;
if (str.length>30){
str=str.substring(0,30)+' ...';
}
return str;
}
However, it seems that Chart Control width is calculated taking into account old label length. Now I have white area at the left of my bars.
How to solve this?
I found the solution.
I just moved slightly changed function from Extension Points (baseAxisLabel_text) to baseAxisTickFormatter (Advanced Properties of the chart control)
function(v){
if (v.length>30){
v=str.substring(0,30)+' ...';
}
return v;
}

ios-charts How to invalidate/redraw after setting data

See Updates At Bottom (4/30/2015)
I'm implementing a Pie Chart in Swift for iOS using ios-charts, and have chosen to customize the legend. Of note, the chart is displayed within a cell of a UICollectionView. The problem is that on first display, the custom legend content is not being displayed. Instead, I get legend content generated from the data.
If I scroll the view off-screen, and then scroll it back onto the screen, the proper custom legend is displayed. So, I'm guessing that I need to force a redraw/relayout/re-something after setting my custom legend. I haven't figured out how to do that. Does anyone have an idea? Am I completely missing something? Thanks!
Chart on initial display - data-generated (wrong) legend
Chart after scrolling off and back onto the screen - (proper legend)
Here's my code for drawing this chart:
func initChart(pieChart: PieChartView) {
numFormatter.maximumFractionDigits = 0
pieChart.backgroundColor = UIColor.whiteColor()
pieChart.usePercentValuesEnabled = false
pieChart.drawHoleEnabled = true
pieChart.holeTransparent = true
pieChart.descriptionText = ""
pieChart.centerText = "30%\nComplete"
pieChart.data = getMyData()
// Setting custom legend info, called AFTER setting data
pieChart.legend.position = ChartLegend.ChartLegendPosition.LeftOfChartCenter
pieChart.legend.colors = [clrGreenDk, clrGold, clrBlue]
pieChart.legend.labels = ["Complete","Enrolled","Future"]
pieChart.legend.enabled = true
}
func getMyData() -> ChartData {
var xVals = ["Q201","R202","S203","T204","U205", "V206"]
var courses: [ChartDataEntry] = []
courses.append(ChartDataEntry(value: 3, xIndex: 0))
courses.append(ChartDataEntry(value: 3, xIndex: 1))
courses.append(ChartDataEntry(value: 4, xIndex: 2))
courses.append(ChartDataEntry(value: 4, xIndex: 3))
courses.append(ChartDataEntry(value: 3, xIndex: 4))
courses.append(ChartDataEntry(value: 3, xIndex: 5))
let dsColors = [clrGreenDk, clrGreenDk, clrBlue, clrBlue, clrGold, clrGold]
let pcds = PieChartDataSet(yVals: courses, label: "")
pcds.sliceSpace = CGFloat(4)
pcds.colors = dsColors
pcds.valueFont = labelFont!
pcds.valueFormatter = numFormatter
pcds.valueTextColor = UIColor.whiteColor()
return ChartData(xVals: xVals, dataSet: pcds)
}
Update 4/30/2015
Based on discussion with author of MPAndroidChart (on which ios-charts is based), it appears there is not a point in the chart display lifecycle where one can override the legend on "first draw". Basically, the chart is rendered when it is created, no matter what. If you set data on the chart, the chart uses that data to create the legend and then renders. It isn't possible to change the legend between the point of setting data, and the point of chart rendering.
setNeedsDisplay()
Potentially, one can wait for the chart to render, update the legend, and then call chart.setNeedsDisplay() to signal the chart to redraw. Sadly, there's a timing problem with this. If you call this method immediately after rendering the chart, it either doesn't fire or (more likely) it fires too soon and is effectively ignored. In my code, placing this call within viewDidLoad or viewDidAppear had no effect. However...
Building the same chart in Java for Android (using MPAndroidChart) results in the same issue. After messing around for a bit, I noted that if I called the chart.invalidate() after a delay (using Handler.postDelayed()), it would fire properly. It turns out a similar approach works for ios-charts on iOS.
If one uses GCD to delay the call to setNeedsDisplay(), for even a few milliseconds after the rendering, it seems to do the trick. I've added the following code immediately after initializing the chart's view in my ViewController ("cell" is the UICollectionViewCell containing the chart view):
delay(0.05) {
cell.pieChartView.legend.colors = [self.clrGreenDk, self.clrGold, self.clrBlue]
cell.pieChartView.legend.labels = ["Complete","Enrolled","Future"]
// Re-calc legend dimensions for proper position (Added 5/2/2015)
cell.pieChartView.legend.calculateDimensions(cell.pieChartView.labelFont!)
cell.pieChartView.setNeedsDisplay()
}
Using the awesome "delay" method from this SO post: https://stackoverflow.com/a/24318861
Obviously, this is a nasty hack, but it seems to do the trick. I'm not sure I like the idea of using this hack in production, though.
For any Android folk who stumble on this post:
The following code achieves the same effect using MPAndroidChart:
// Inside onCreate()
pie = (PieChart) findViewById(R.id.chart1);
configPieChart(pie);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
String[] legLabels = new String[]{"Complete","Enrolled","Future"};
ArrayList<Integer> legColors = new ArrayList<Integer>();
legColors.add(blue);
legColors.add(gold);
legColors.add(green);
pie.getLegend().setPosition(Legend.LegendPosition.LEFT_OF_CHART_CENTER);
pie.getLegend().setColors(legColors);
pie.getLegend().setLabels(legLabels);
pie.invalidate();
}
}, 20);
I am the author of ios-charts, and we're working on features for customizing the legend data, without those "hacks".
In the latest commits to ios-charts, you can already see extraLabels and extraColors properties that add extra lines to the legend, and a setLegend function that allows you to set a custom data entirely.
This will soon be added to the Android version as well.
Enjoy :-)

Isn't there an "auto disposition" method?

I have a graph with nodes and edges and I want to display them.
Isn't there any function which, given this graph, displays it without me to give exact coordinates?
yes, you can use the auto layout
http://jgraph.github.io/mxgraph/docs/js-api/files/layout/mxCompactTreeLayout-js.html
this url construct a compact tree layout.
var layoutMgr = new mxLayoutManager(graph);
layoutMgr.getLayout = function(cell) {
return layout;
};

animation for zoom in and zoom out in android for imageview

How do i set zoom in and zoom out when click on imageview?I want my program to react when user click on imageview must get large to some extent and can move imageview on that screen and sometime it reduce the size along when it move on touch anywhere on the screen .when click again is go resume original size what do i do?
As far as I know there are two ways.
The first way:
Make a new folder in res called 'anim'. Than make a xml file inside, for example zoomin.xml. Afterwards put the following code inside.
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="1"
android:toXScale="5"
android:fromYScale="1"
android:toYScale="5"
android:pivotX="50%"
android:pivotY="50%"
android:duration="1000"
android:fillAfter="true">
</scale>
Make another one for zoom out, but with reversed values.
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="5"
android:toXScale="1"
android:fromYScale="5"
android:toYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:duration="1000"
android:fillAfter="true">
</scale>
You can change the values according to your needs. I think that they are self-explanatory.
And now in your java code.
ImageView imageView = (imageView)findViewById(R.id.yourImageViewId);
Animation zoomin = AnimationUtils.loadAnimation(this, R.anim.zoomin);
Animation zoomout = AnimationUtils.loadAnimation(this, R.anim.zoomout);
imageView.setAnimation(zoomin);
imageView.setAnimation(zoomout);
Now you only need to keep track which is the current state. And for each state execute this lines of codes:
imageView.startAnimation(zoomin);
and
imageView.startAnimation(zoomout);
For example:
imageView.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
if(!pressed) {
v.startAnimation(zoomin);
pressed = !pressed;
} else {
v.startAnimation(zoomout);
pressed = !pressed;
}
}
});
The other way is described here : http://developer.android.com/training/animation/zoom.html.
You can make this by following this guide easily
http://developer.android.com/training/animation/zoom.html
shortly you should use third imageview which is invisible when the user touches any imageview you want, you can display it by using animation in the imageview which is invisible.