I put 8 charts in my form . I want to set some parameters of the charts in a loop , not one by one . Charts don't belong to Controls . Any ideas ?
You can add all your Chart objects to a Collection i.e. to a List<Chart> and iterate over them to modify all their properties like this:
do this in your form constructor
List<Chart> _charts = new List<Chart>();
_charts.Add(chart1);
_charts.Add(chart2);
Call this method when you want to change all background colors to black.
void changeChartsBackground()
{
foreach(var chart in _charts)
{
chart.Background = Color.Black;
}
}
Finally it looks like this:
List<Control> _charts = new List<Control>();
_charts.Add(chart1);
_charts.Add(chart2);
foreach (Control _chart in _charts)
{
_chart.BackColor = Color.Blue;
}
Related
I am trying to implement my first unity editor code to make a custom array property drawer with indented named entries and indented and dynamicaly resized value fields.
I am using the following simple git solution as base for my code, which allows to set the labels of an array in the inspector : HERE
replacing the example shown in the gitHub solution, I am working with this enum as my array element name container:
[System.Serializable]
public enum HealthNames
{
General,
Head,
Body,
RightArm,
LeftArm,
Rightleg,
leftLeg,
}
and sets it up on a array in a monobehaviour class :
[ LabeledArray( typeof( HealthNames ) ) ]
public int[] m_aHealth = new int[ Enum.GetNames( typeof( HealthNames ) ).Length ];
I have added EditorGUI.indentLevel++; and EditorGUI.indentLevel--; at the start and end of the try statement to indent the label of the array elements, making them stand out from the size property.
Going from there, I have searched ways to add an indent on the elements' value fields or remove it from the size property's value field. but have found no answer using EditorGUI
I also looked to be able to resize all value fields dynamicaly, but there again, no answer came using EditorGUI only. there is no way to use EditorStyle.AnyField.WordWrap = true; on a propertyfield. Passing the PropertyField to an IntField, using a EditorStyles.NumberField and setting having its wrodwrapping set to true beforehand has no effect.
I also have found a small number of EditorGUILayout from a few years ago, but which do not work since the solution is built from the ground with EditorGUI
In hope of your enlightment on the matter
If I understand you correctly you want the labels and the value fields indented.
I think it could be done like e.g.
private const int INDENT = 15;
public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(rect, label, property);
var fieldsRect = new Rect(rect.x + INDENT, rect.y, rect.width - INDENT, rect.height);
try
{
var path = property.propertyPath;
int pos = int.Parse(path.Split('[').LastOrDefault().TrimEnd(']'));
EditorGUI.PropertyField(fieldRect, property, new GUIContent(ObjectNames.NicifyVariableName(((LabeledArrayAttribute)attribute).names[pos])), true);
}
catch
{
EditorGUI.PropertyField(fieldRect, property, label, true);
}
EditorGUI.EndProperty();
}
I just started using AmCharts and have setup two line plots, one on top of the other, with their respective scrollbars.
Now, I want to "link" the scrollbars of both plots, so that if I move the scrollbar on the chart1, I'll get the same date range on the chart2. I imagine this shouldn't be too difficult with a listener, a get value function and a set value function, but I'm unable to find how to get the start/end values of the scrollbar so that I can play with them.
Any help would be appreciated.
thanks
There is a demo for this in the AmCharts Knowledge Base
https://www.amcharts.com/kbase/share-scrollbar-across-several-charts/
This is the code that is syncing the scrollbars, (I have added the annotations):
Create an array to populate with your charts
var charts = [];
Create how ever many charts you need
charts.push(AmCharts.makeChart("chartdiv", chartConfig));
charts.push(AmCharts.makeChart("chartdiv2", chartConfig2));
charts.push(AmCharts.makeChart("chartdiv3", chartConfig3));
Iterate over the charts, adding an event listener for "zoomed" which will share the event handler
for (var x in charts) {
charts[x].addListener("zoomed", syncZoom);
}
The event handler
function syncZoom(event) {
for (x in charts) {
if (charts[x].ignoreZoom) {
charts[x].ignoreZoom = false;
}
if (event.chart != charts[x]) {
charts[x].ignoreZoom = true;
charts[x].zoomToDates(event.startDate, event.endDate);
}
}
}
I need to manipulate the text elements of the first and last tick of an axis to bring them more towards the center.
I am trying to select them, one at the time, with something like svg.select('.tick:last-child text') but it doesn't work. I'd then apply .transform('translate(4,0)')...
Am I doing something wrong? How can I achieve this?
One thing you could do is to create custom sub-selections by adding methods to d3.selection.prototype. You could create a selection.first() method that selects the first item in a selection, and a selection.last() method that selects the last item. For instance:
d3.selection.prototype.first = function() {
return d3.select(this[0][0]);
};
d3.selection.prototype.last = function() {
var last = this.size() - 1;
return d3.select(this[0][last]);
};
This would let you do the following:
var tickLabels = svg.selectAll('.tick text');
tickLabels.first()
.attr('transform','translate(4,0)');
tickLabels.last()
.attr('transform','translate(-4,0)');
Of course, you need to make sure that you only have one axis if you do it that way. Otherwise, specify the axis in your initial selection:
var tickLabels = svg.selectAll('.axis.x .tick text');
HERE is an example.
Here's the cleanest method I've found:
g.selectAll(".tick:first-of-type text").remove();
g.selectAll(".tick:last-of-type text").remove();
As google brought me here, I also want to add a cleaner method to what Adam Grey wrote.
Sometimes you just want to do it without taking a reference of selectAll .
svg.selectAll('.gridlines').filter(function(d, i,list) {
return i === list.length - 1;
}).attr('display', 'none');
the 3rd parameter of the filter function gives you the selected List of elements.
They don't exist in d3 specifically, but you can use the .firstChild and .lastChild methods on a node.
You can first select all of the parents of the node, and then operate within the scope of a .each() method, like so:
d3.selectAll('.myParentElements').each(function(d,i){
var firstChild = this.firstChild,
lastChild = this.lastChild;
//Do stuff with first and last child
});
Within the scope of .each(), this refers to the individual node, which is not wrapped by a d3 selection, so all of the standard methods on a node are available.
Using .filter() with a function also works selection.filter(filter) :
var gridlines;
gridlines = svg.selectAll('.gridlines');
gridlines.filter(function(d, i) {
return i === gridlines.size() - 1;
}).attr('display', 'none');
It's for D3.js v4
d3.selection.prototype.first = function() {
return d3.select(
this.nodes()[0]
);
};
d3.selection.prototype.last = function() {
return d3.select(
this.nodes()[this.size() - 1]
);
};
Example:
var lines = svg.selectAll('line');
lines.first()
.attr('transform','translate(4,0)');
lines.last()
.attr('transform','translate(-4,0)');
Here is another, even though I used Fered's solution for a problem I met.
d3.select(d3.selectAll('*').nodes().reverse()[0])
I have problem with changing this image list provider in to thumbnail provider. In case of need I will post View for it too.
public Object[] getElements(Object inputElement) {
if (iDirname == null)
return null;
File dir = new File(iDirname);
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File directory, String filename) {
if (filename.endsWith("jpg") || (filename.endsWith("bmp")) || (filename.endsWith("png") || (filename.endsWith("JPG") || (filename.endsWith("BMP")) || (filename.endsWith("PNG")))))
return true;
else
return false;
}
};
String[] dirList = null;
if (dir.isDirectory()) {
dirList = dir.list(filter);
for (int i=0; i<dirList.length;++i){
//dirList2[i] = new Image(device, dirList2[i]); added this to try passing array of Images - failed.
dirList[i] = iDirname + File.separatorChar + dirList[i];
}
}
return dirList;
}
And the view
public void createPartControl(Composite parent) {
iViewer = new ListViewer(parent);
iViewer.setContentProvider(new DirListProvider());
getSite().setSelectionProvider(iViewer);
makeActions();
hookContextMenu();
contributeToActionBars();
}
I don't know how to change provided path lists to the thumbnail displaying. Should I get the provided content in to Array and iterate through it creating Images? If so how?
Thanks in advance for your help.
EDIT:
I added
ImageDescriptor[] dirList = null;
if (dir.isDirectory()) {
String[] dirList2 = dir.list(filter);
for (int i=0; i<dirList2.length;++i){
dirList[i] = ImageDescriptor.createFromImageData(new ImageData(iDirname + File.separatorChar + dirList2[i]));
//dirList[i] = iDirname + File.separatorChar + dirList[i];
}
}
return dirList;
but this is not showing anything at all.
When you are telling me to use Composite, is it my parent variable? I still don't know how to display the images from paths passed by ListProvider. I am really green in this :/
What you are missing here is a LabelProvider. You can use a LabelProvider to provide an image for each element in your viewer's input.
However, Francis Upton is right, I don't think ListViewer will really suit your needs as you will end up with a single column of images. Although you won't be able to add the images directly to your Composite, you will need to set them as the background image of a label.
There are a couple of other things to consider:
You need to dispose() of your Images once you're done with them as they use up System handles. Therefore you need to keep track of the Images you create in your getElements(Object) method.
If the directories you are reading the images from do not already contain thumbnails, you will need to scale the images before presenting them on your UI.
Remember, the array type you return from your ContentProvider's getElements(Object) method defines the type that will get passed into your LabelProvider's methods. So you started off returning an array of strings representing paths to the images. Your LabelProvider would need to load these into images to be returned from the provider's getImage method - but bear in mind what I said about disposing of these images! Then you switched to returning an Array of image descriptors, in this case you would need to cast your incoming Object to an ImageDescriptor and use that to create the Image in the getImage method. Maybe once you have this working you can think about whether this meets your needs, and then possibly look at doing a different implementation, such as the composite/gridlayout/label approach.
I would not use a ListViewer for this. I would just create a Composite and then using GridLayout set up the number of columns you want and margins and so forth, and then just add the images directly to the composite. As far as I know you cannot put arbitrary things like imagines in an SWT List, so the ListViewer is not going to help you. You can do all of this in the createPartControl method.
i've to create a chart using library JFreeChart, i try this:
TimeSeriesCollection dataset = new TimeSeriesCollection();
ArrayList<MyObject> list = this.FillArray();
MyObject tmp;
String date[];
for(int i=0;i<list.size();i++){
tmp = list.get(i);
ArrayList<MyObject1> obj = this.FillArray1(tmp);
TimeSeries pop = new TimeSeries(tmp.getName(),Day.class);
for(MyObject1 ob1 : obj){
date = ob1.getDate().split("-");
Day day = new Day(Integer.parseInt(date[0]), Integer.parseInt(date[1]), Integer.parseInt(date[2]));
pop.addOrUpdate(day, ob1.getValue());
}
dataset.addSeries(pop);
}
My problem borns when the number of object is very high and legend will cover the panelchart. What can i do? is possible to add a scrollpane to the legend?
Legends are rendered in a LegendTitle, the first Title added to List subtitles when the JFreeChart instance is constructed with the createLegend parameter set to true. Because JFreeChart is not a Container, nor is Title a Component, adding a LegendTitle to a JScrollPane is not supported.
You can always invoke getLegendItems() and render the items in a Scrollable Container such as JList or JTable. To avoid duplication, set createLegend to false.