How to create kendo pie chart with model in MVC - asp.net-mvc-4

I am trying to create a Pie chart through model and controller in MVC using Kendo UI which will show the total for two types of food but I am not able to get the results due to the attached error.
Types to show in pie chart:
1)Beverages and
2)Meals
I am referring to this kind of Chart.
Kendo UI Pie chart
This link has shown multiple graphs using foreach but I am just concerned with only single chart that will differentiate the total earnings from Meals and Beverages.
My controller is:
public ActionResult _SpainElectricityProduction()
{
List<PieGraphModel> objList = new List<PieGraphModel>();
for (int i = 0; i < 2; i++)
{
if (i == 0)
{
objList.Add(new PieGraphModel { coke = 10, pepsi = 20, Type = "Beverages", total = 30 });
}
else
{
objList.Add(new PieGraphModel { chiniese = 50, italian = 40, Type = "Meals", total = 90 });
}
}
return Json(objList);
}
#(Html.Kendo().Chart<MvcRepo_Kendo.Models.PieGraphModel>()
.Name("chart")
.HtmlAttributes(new { #class = "small-chart" })
.Legend(legend => legend
.Visible(false)
)
.DataSource(ds =>
{
ds.Read(read => read.Action("_SpainElectricityProduction", "Home"));
}
)
.Series(series => series
.Pie(model => model.total)
.Padding(0)
)
.Tooltip(tooltip => tooltip
.Visible(true)
.Format("{0:N0}")
.Template("#= category # - #= kendo.format('{0:P}', percentage)#")
)
)

The Kendo method for generating a pie chart expects and array of objects, with each object representing one segment in the pie chart. Each object must contain a property for the value (the percentage that each segment will occupy in the whole) and the name of the segment. In addition, it can contain a property for the color (to override the default color) and a bool to indicate if the segment is 'exploded'.
Your PieGraphModel should look like (you can name the properties whatever you want)
public class PieGraphModel
{
public string Name { get; set; }
public float Value { get; set; }
public string Color { get; set; } // optional
public bool Explode { get; set; } // optional
}
and to create a pie chart with 2 segments, "Meals" and "Beverages", being 1/3 and 2/3 respectively, your controller method would be
List<PieGraphModel> model = new List<PieGraphModel>()
{
new PieGraphModel(){ Name = "Meals", Value = 33.33F },
new PieGraphModel(){ Name = "Beverages", Value = 66.67F }
};
return Json(model);
and in the view
.Series(series => series
.Pie(m => m.Value, m => m.Name)
.Padding(0)
)
Note that the expressions must match the names of the properties. If you also wanted to specify Color and Explode, the it would be
.Series(series => series
.Pie(m => m.Value, m => m.Name, m => m.Color, m => m.Explode)
.Padding(0)
)
which would output this pie chart if the data was
List<PieGraphModel> model = new List<PieGraphModel>()
{
new PieGraphModel(){ Name = "Hydro", Value = 22.0F, Color = "#03a9f4", Explode = true },
new PieGraphModel(){ Name = "Solar", Value = 2.0F, Color = "#ff9800"},
new PieGraphModel(){ Name = "Nuclear", Value = 49.0F, Color = "#fad84a"},
new PieGraphModel(){ Name = "Wind", Value = 27.0F, Color = "#4caf50"}
};

Related

OxyPlot: How to calculate in TrackerFormatString?

I try to create a line series where not only x- and y-values shall be displayed in the tracker, but one more property:
var series = new LineSeries {TrackerFormatString = "X:{2}\nY:{4}\nZ:{2*(1-4)}"};
series.Points.AddRange(...);
I want another property Z = (1-Y) * X to be displayed in the third row of the tracker. How is this possible?
It is possible by creating a custom
public class CustomDataPoint : IDataPointProvider
{
public double X { get; }
public double Y { get; }
public double Z{ get; }
public CustomDataPoint(double x, double y)
{
X = x;
Y = y;
Z = (1 - Y) * X;
}
public DataPoint GetDataPoint()
{
return new DataPoint(X, Y);
}
}
And then add it to the series:
var series = new LineSeries {TrackerFormatString = "X:{2}\nY:{4}\nZ:{Z}"};
series.ItemsSource = new [] {
new CustomDataPoint(...),
new CustomDataPoint(...)
};
Note that you need to use the ItemsSource property. You cannot simply add points with series.Point.AddRange(...).

Raven DB filter on subset of array items and sort on the cheapest of the filter results items

Assuming i have an parent class that I filter on various properties, one of which is a property that is an array of items .
Now say that i want to only return the parent item if my array of items as above a min value and below a max value ...that's fine i can work that bit out;
What if i then want to then sort on the filtered result set of those items
I made a c# fiddle example to show what im trying to achieve :
https://dotnetfiddle.net/mV4d28
(note that foo2 is returned first even though foo1 has items in its array that are less that those in foo2)
As i need to do this using a index i need the index to be able to compute the order by based on the filter criteria used in my query.
I know elasticsearch has an inner hits function that dose this and mongo has pipelines which also dose this so im sure Raven must have a way of doing this too ?
I was hoping using just index and a transform with prams i could achieve this so I tried it:
my index and transform look like this
public class familyTransfrom : AbstractTransformerCreationTask<ParentItem>
{
public class Result : ParentItem{
public double[] ChildItemValuesFiltered { get; set; }
}
public familyTransfrom(){
TransformResults = parents => from parent in parents
let filterMinValue = Convert.ToDouble(ParameterOrDefault("FilterMinValue", Convert.ToDouble(0)).Value<double>())
let filterMaxValue = Convert.ToDouble(ParameterOrDefault("FilterMaxValue", Convert.ToDouble(9999)).Value<double>())
select new Result{
ParentItemId = parent.ParentItemId,
ParentItemName = parent.ParentItemName,
ParentItemValue = parent.ParentItemValue,
//ChildItemValuesFiltered = parent.ChildItems.Where(p => p.ChildItemValues.Any(y => Convert.ToDouble(y) >= Convert.ToDouble(filterMinValue) && Convert.ToDouble(y) <= Convert.ToDouble(filterMaxValue))).SelectMany(t => t.ChildItemValues).ToArray<double>(),
ChildItemValuesFiltered = parent.ChildItems.SelectMany(p => p.ChildItemValues.Where(y => Convert.ToDouble(y) >= Convert.ToDouble(filterMinValue) && Convert.ToDouble(y) <= Convert.ToDouble(filterMaxValue))).ToArray<double>(),
ChildItems = Recurse(parent, x => x.ChildItems).Select(y => y).ToArray()
};
}
}
public class familyIndex : AbstractIndexCreationTask<ParentItem>{
public class Result : ParentItem {
public double[] ChildItemValues { get; set; }
}
public familyIndex(){
Map = parents => from parent in parents
select new Result{
ParentItemId = parent.ParentItemId,
ParentItemName = parent.ParentItemName,
ParentItemValue = parent.ParentItemValue,
ChildItemValues = parent.ChildItems.SelectMany(p => p.ChildItemValues.Select(y => y)).ToArray(),
ChildItems = Recurse(parent, x => x.ChildItems).Select(y => y).ToArray()
};
Index("ParentItemId", FieldIndexing.Analyzed);
Index("ParentItemName", FieldIndexing.Analyzed);
Index("ParentItemValue", FieldIndexing.Analyzed);
Index("ChildItemValues", FieldIndexing.Analyzed);
Index("ChildItems", FieldIndexing.Analyzed);
}
}
my query is as follows , (this is using the live raven playground so this should just work out of the box it you want to use it)
using (IDocumentStore store = new DocumentStore { Url = "http://live-test.ravendb.net/", DefaultDatabase = "altha" })
{
store.Initialize();
using (IDocumentSession session = store.OpenSession())
{
if(1 == 2){
//foreach (ParentItem element in data.OfType<ParentItem>()) {
// session.Store((ParentItem)element);
// session.SaveChanges();
//}
new familyIndex().Execute(store);
new familyTransfrom().Execute(store);
}else{
double filterMinValue = 3.0;
double filterMaxValue = 4.0;
var results = session
.Advanced
.DocumentQuery<familyIndex.Result,familyIndex>()
.WhereBetweenOrEqual("ChildItemValues", filterMinValue, filterMaxValue)
.SetResultTransformer<familyTransfrom, familyTransfrom.Result>()
.SetTransformerParameters(new Dictionary<string, RavenJToken> {
{ "FilterMinValue", filterMinValue },
{ "FilterMaxValue", filterMaxValue } })
.OrderBy("ChildItemValues")
.OfType<ParentItem>().ToList();
results.Dump();
}}
}
What i found was i cant use "ChildItemValuesFiltered" from the transform result as its not index. So unless i can order by the result of a transform ? i couldn't get this to work as although it filters it dosnt order correctly.
Is there another to achieve what i want using projections or intersection or rank or reduce try method ?
I was thinking if i had to perhaps i could use https://ravendb.net/docs/article-page/3.5/csharp/indexes/querying/sorting#custom-sorting
and do something like this:
public class SortByNumberOfCharactersFromEnd : IndexEntriesToComparablesGenerator
{
private readonly double filterMinValue;
private readonly double filterMinValue;
public SortByNumberOfCharactersFromEnd(IndexQuery indexQuery)
: base(indexQuery)
{
filterMinValue = IndexQuery.TransformerParameters["FilterMinValue"].Value<double>(); // using transformer parameters to pass the length explicitly
filterMaxValue = IndexQuery.TransformerParameters["FilterMaxValue"].Value<double>();
}
public override IComparable Generate(IndexReader reader, int doc)
{
var document = reader.Document(doc);
double[] childItemValues = (double[])document.GetValues("ChildItemValuesFiltered").Select(double.Parse).ToArray(); // this field is stored in index
return childItemValues.Where(x => x >= min && x <= max).Min();
}
}
then do a where filter and order by clause using index and transform passing in the same prams that i use in the where filter . however im not sure if this would work ?
More importantly im not sure how i go about getting the sort dll into the plugins ie what name space should the class go under, what name spaces dose it need to import, what assembly name dose it need to use etc
According to https://ravendb.net/docs/article-page/3.5/csharp/server/plugins/what-are-plugins i just need to drop the dll in and raven will this this up , however i cant seem to find what name space i need to reference for IndexEntriesToComparablesGenerator ?
im using linqpad 5 to test my stuff ...so in order to use the custom order i have to reference the class
any tips or advice or how to guild/examples welcome
so it didn't occur to me that i could do the filtering in the transform
TransformResults = parents => from parent in parents
let filterMinValue = Convert.ToDouble(ParameterOrDefault("FilterMinValue", Convert.ToDouble(0)).Value<double>())
let filterMaxValue = Convert.ToDouble(ParameterOrDefault("FilterMaxValue", Convert.ToDouble(9999)).Value<double>())
select new {
ParentItemId = parent.ParentItemId,
ParentItemName = parent.ParentItemName,
ParentItemValue = parent.ParentItemValue,
//ChildItemValuesFiltered = parent.ChildItems.Where(p => p.ChildItemValues.Any(y => Convert.ToDouble(y) >= Convert.ToDouble(filterMinValue) && Convert.ToDouble(y) <= Convert.ToDouble(filterMaxValue))).SelectMany(t => t.ChildItemValues).ToArray<double>(),
ChildItemValuesFiltered = parent.ChildItems.SelectMany(p => p.ChildItemValues.Where(y => Convert.ToDouble(y) >= Convert.ToDouble(filterMinValue) && Convert.ToDouble(y) <= Convert.ToDouble(filterMaxValue))).ToArray<double>(),
ChildItems = Recurse(parent, x => x.ChildItems).Select(y => y).ToArray()
} into r
where r.ChildItemValuesFiltered.Length > 0
orderby r.ChildItemValuesFiltered.Min()
select r;
This gives me what i wanted, here are the sample query:
http://live-test.ravendb.net/databases/altha/indexes/familyIndex?start=0&pageSize=25&resultsTransformer=familyTransfrom&tp-FilterMinValue=3&tp-FilterMaxValue=4
i cant take credit for this as guys at raven helped me but sharing the knowledge for others

How to use GroupFormatter with ObjectListView control

I cannot seem to find anywhere, any examples on how to make use of the GroupFormatter delegate to allow me to add footers to my groups when using the ObjectListView control.
Does anyone have any examples that could demonstrate this? I want to remove the text from the group header and add a footer (different text per footer). As well as changing font, etc.
Any examples would be very helpful.
You can analyze the code for the
public void MakeGroupies<T>(T[] values, string[] descriptions, object[] images, string[] subtitles, string[] tasks)
method of the ObjectListView class. That explicitly sets the GroupKeyGetter, GroupKeyToTitleConverter and GroupFormatter property delegates.
This is C# but your VB adaptation should be straightforward. I am using this small test class as the object type to bind to the list view.
public class TestClass
{
private readonly string _s;
private readonly float _f;
public TestClass( string p1, float p2 )
{
this._s = p1;
this._f = p2;
}
[OLVColumn(DisplayIndex = 1, Name="S", Title="String")]
public string S {get {return this._s;}}
[OLVColumn( DisplayIndex = 2, Name = "F", Title = "Float" )]
public float F {get {return this._f;}}
}
So as not to manually define column traits I am using attributes inside the bound object and a
BrightIdeasSoftware.Generator.GenerateColumns( this.olv, typeof( TestClass ) );
call in the form/user control where I am using the list view. In fact here is the method that completely isolates ObjectListView configuration:
void SetData( TestClass[] objects )
{
// build list columns
Generator.GenerateColumns( this.olv, typeof( TestClass ) );
// use groups and make current column the priimary sort column
this.olv.ShowGroups = true;
this.olv.SortGroupItemsByPrimaryColumn = false;
// loop through columns and set properties
foreach( OLVColumn col in this.olv.Columns )
{
col.Groupable = true;
col.Sortable = true;
if( col.Name == "F" )
{
col.MakeGroupies<float>( new float[] { 10f, 100f, 1000f }, new string[] { "<10", "10-100", "100-1000", ">1000" } );
}
else if( col.Name == "S" )
{
col.UseInitialLetterForGroup = false;
//
col.GroupKeyGetter = ( obj ) =>
{
TestClass tc = (TestClass)obj;
switch( char.ToLower( tc.S[0] ) )
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u': return true;
default: return false;
}
};
//
col.GroupKeyToTitleConverter = ( o ) => { bool b = (bool)o; return b ? "vowel" : "consonant"; };
//
col.GroupFormatter = ( /*OLVGroup*/ group, /*GroupingParameters*/ parms ) =>
{
string s = string.Format ("{0} {1}", group.GroupId, group.Id);
//group.BottomDescription = "BottomDescription: " + s;
//group.TopDescription = "TopDescription: " + s;
group.Footer = "Footer: " + s;
};
}
}
//
this.olv.RebuildColumns();
//
this.olv.SetObjects( objects );
}
You will definitely have one different footer per each group.

Binding The Collection of data in drop down list in mvc4

I am having Code like below in my view.
#if (!Model.DisableBuyButton || !Model.DisableWishlistButton)
{
<div class="qutblk">
<span>#Html.LabelFor(model => model.EnteredQuantity, new { #class = "input-small" }, " :")</span>
#if (Model.AllowedQuantities.Count > 0)
{
#Html.DropDownListFor(model => model.EnteredQuantity, Model.AllowedQuantities, new { #class = "input-small" })
}
else
{
#Html.TextBoxFor(model => model.EnteredQuantity, new { #class = "input-small" })
}
} #Html.Widget("productdetails_add_info")
</div>
Here if i have the ALLOWEDQUANTITIES.COUNT is more then 0.I need drop down list for quantities.
For example if the quantity is 5 i need 1,2,3,4,5 numbers in my drop down list.And if the quantity is 7 i need 1,2,3,4,5,6,7 numbers in my drop down.
But my problem is i am not able to bind the data like numbers in my drop down that means if the quantity is 5 it simply displaying only 5 number in drop down list not displaying 1,2,3,4,5.
You may try something like this:
public static class MyLists
{
public static List<SelectListItem> GetList()
{
List<SelectListItem> result = new List<SelectListItem>(int AllowedQuantities)
for(int i = 0; i < AllowedQuantities; i++)
{
var number = i + 1;
var item = new SelectListItem {text = number.ToString(), value = number.ToString()};
result.Add(item);
}
return result
}
}
In your view:
#Html.DropDownListFor(model => model.EnteredQuantity, MyLists.GetList(model.EnteredQuantity), new { #class = "input-small" })

NHibernate Projections (QueryOver.SelectList) limits

I'm new on stackoverflow and i hope this question will be appreciated.
Simply said: I select everything from table x left outer join table y. Table x has way too many columns so i make new object x. This object is used for the Projection. I can project every single column of table x i want. But when i try to project/select an collection (the collection of table y) then i get the same error: 'Index was outside the bounds of the array'.
My question: Does NHibernate support to select/project a collection at all? Because i've seen this question multiple times by searching on google (and stackoverflow), but none of those questions were answered.
Code example:
public class X
{
public virtual int ID { get; set; }
public virtual int IDontNeedMoreInfoAboutClassXItTakesToMuchTimeToRetrieve { get; set; }
public virtual IList<Y> YCollection { get; set; }
}
public class Y
{
public virtual int YID { get; set; }
}
public class XRepository{
public ISession Session {get; set;}
public IList<X> Get()
{
X xAlias = null;
Y yAlias = null;
X resultAlias = null;
return Session.QueryOver<X>()
.JoinAlias(() => xAlias.YCollection, () => yAlias, JoinType.LeftOuterJoin)
.SelectList(list => list
.SelectGroup(() => xAlias.ID).WithAlias(() => resultAlias.ID)
.SelectGroup(() => xAlias.YCollection).WithAlias(() => resultAlias.YCollection)) // Index was outside the bounds of the array
.TransformUsing(Transformers.AliasToBean<X>()).List<X>();
}
}
the results returned have to be grouped with the contents intact (so sql is out since it can only aggregate over the grouped items) but NHibernate can only do this for m,apped entities because there it knows the identity to group by. It is simple to do it manually
Y yAlias = null;
var tempResults = Session.QueryOver<X>()
.JoinAlias(x => x.YCollection, () => yAlias, JoinType.LeftOuterJoin)
.SelectList(list => list
.Select(() => xAlias.Id)
.Select(() => xAlias.Name)
...
.Select(() => yAlias.Id)
...
.ToList<object[]>()
List<X> results = new List<X>(100); // switch to Hashset if too slow and order does not matter
foreach(var row in tempResults)
{
Y y = new Y { Id = (long)row[4], ... };
X x = results.FirstOrDefault(x => x.Id == (long)row[0]));
if (x != null)
x.YCollection.Add(y);
else
results.Add(new X { Id = (long)row[0], ..., YCollection = { y } };
}
return results;