How to resize chart more than screen resolution? - c#

I have a C# 4.7 WinForms application with line chart. I want to save chart image with very large resolution e.g 10000x2000. Here is what I have archived:
Form1.Width = 3860; //my screen width resolution - maximum allowed
Form1.Height = 1080; //my screen height resolution - maximum allowed
chart1.Dock = DockStyle.Fill;
chart1.SaveImage(saveFile.FileName, ChartImageFormat.Jpeg);
That code saves jpeg image with 3860x1080 resolution and i can zoom in points I need. But it is not enough and I want to enlarge my form or chart to
get an image like 10000x2000, VS says it cannot be larger than my screen.
I have a lot of data on this chart, so bigger form provides me with more data on a chart. Picture is required for other people to see the maximum info.
How can I do it?

This is quite simple.
All you need to do is create the Chart in code without displaying it on screen.
Now you can size it as needed..:
Chart bigChart = new Chart();
bigChart.ChartAreas.Add("ca");
Series s1 = bigChart.Series.Add("s1");
s1.BorderWidth = 5;
s1.ChartType = SeriesChartType.Line;
// testdata
Random rnd = new Random(8);
for (int i = 0; i < 111; i++)
{
s1.Points.AddXY(rnd.Next(123) + i, rnd.Next(12 * i)) ;
}
bigChart.Size = new Size(10000, 8000);
bigChart.SaveImage(filename, ChartImageFormat.Png);
A few notes:
You may want to add a Legend as well, as the dynamically created Chart has none of the default elements..
If you want to you can use a chart you have, serialize its content to a file (or stream) and then load (deserialize) it into the big chart..
The automatic smartness of MSChart tends to hit some limit when the sizes grow a lot; so brace yourself for tweaking some settings for line width, Fonts etc..
You also may want to load the saved image and set the dpi to a bigger values than the default, which is the screen resolution..
Final remark: Sometimes it is better to save the chart as a vector format; these are also provided in the SaveImage method.
Update: Maybe you want to combine vector and pixel formats as in Jimi's last comments.
You may want to study this post which discusses a few general options.

Related

Add images on chart control

I'm not sure if I titled the question correctly so it would be better if I explained what I'm trying to do. I want to add some images on chart control and
around their to draw graphics.
I want to display the layout of the sensors on the coordinate plane defined by coordinates, while noting the location of geographic objects (forest, river, etc.). These objects will be images which I want to add to the chart/
How can I do it? It is possible?
If you show us an example we may be able to help to find the best way.
There are several options.:
You can place image controls like PictureBox or Panel on the Chart by adding them to the chart's Controls collection
You can draw them in the Pre- or PostPaint event
You can assemble a BackImage that contains all the Images you want to place around the chart.
You can add ImageAnnotations to the chart. (Recommended)
The latter obviously is the one that is best integrated.
Here is an example:
We start by adding the images we want to use to the Chart's Images collection:
List<string> imgFiles = new List<string>()
{ yourImageFileName1, ...};
for (int i = 0; i < imgFiles.Count; i++)
{
Image img = Bitmap.FromFile(imgFiles[i]);
chart1.Images.Add(new NamedImage("Image" + i, img));
}
Note the NamedImage class used here. It allows you to refer to the images by a string; pick better names! Maybe Path.GetFileNameWithoutExtension(imgFiles[i]) - Also note that you must not Dispose of the Images or else they will disappear!
Next make make a little room at the right side of the chart by reducing the ChartArea's size:
ChartArea ca = chart1.ChartAreas[0];
ca.Position = new ElementPosition(5,5,70,90);
Note the values are percentages of the Chart's ClientSize, so they will grow and shrink when resizing the Chart!
Finally we can add them all. You will want to add them at specific positions. I add them at some space to the right and also make them moveable:
foreach (NamedImage img in chart1.Images)
{
ImageAnnotation ia = new ImageAnnotation();
ia.Image = img.Name;
ia.AllowMoving = true;
ia.X = 77;
ia.Y = 15 * chart1.Images.IndexOf(img) + 5;
chart1.Annotations.Add(ia);
}
Now you should see the Annotions. And if you add this event:
private void chart1_AnnotationPositionChanging(object sender,
AnnotationPositionChangingEventArgs e)
{
testLabel.Text = e.Annotation.X + " " + e.Annotation.Y;
}
..you will see just what the numbers for the best position are. Eventually you will not keep them moveable, of course..
Note the the Annotations' position is also in percentages, so they will move along nicely, when the chart get resized! You may also scale the Images by setting the Width and Height; this is a little tricky, as it will also be in percent (and not as the docs falsely state in pixels). You would probably want to loop over the ImageAnnotations and rescale them in the Resize event..: ia.Height = ia.Width * chart1.Width / chart1.Height;
Also note that there are other ways to position annotations, like anchored to datapoints, but this seem the best for a static adornment.

Dynamic graphs using C# (To be saved as a PNG Format)

I have to generate dynamic graphs on the fly, save it as a PNG image format (Transparent background) to be embedded on to a PDF.
The problem is, the graph will not be displayed on a control in the page (without a chart control in the WebForm) and should be generated from an underlying information and should be embedded while creating the PDF.
The libraries for the PDFs and PDF generation is all in place.
I would like to know how to generate a dynamic graph (Bar graph, Pie Graph) 3D or Simple graph without a chart control in place and be able to save it as an image with transparent background (.PNG).
The reason being, the PDF template has numerous layer shading, hence the background around the graph image should be transparent, something similar to the below image.
I have tried generating a dynamic bar graph similar to the example in the below link but the Image doesn't look promising
https://2leggedspider.wordpress.com/2004/11/21/generating-a-dynamic-bar-graph-using-aspnet-and-c/
Any help regarding the functionality is deeply appreciated. Thank you in advance.
Update: Wednesday 16th March 2016
With TaW's answer and updates I have been able to draw the required graph and below is the update with answer to the same question I asked
Add references to System.Windows.Forms and System.Windows.Forms.DataVisualization
Add below namespaces
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
And below method would give you the Pie Chart with smooth edges as shown in the picture
void Create3DPieChart()
{
/* Utilize the Chart class available in System.Windows.Forms.DataVisualization.Charting */
Chart chart = new Chart();
/* Add a chart area to the chart */
ChartArea CA = chart.ChartAreas.Add("A1");
/* Add data series to the chart and specify the type of Series */
Series S1 = chart.Series.Add("S1");
S1.ChartType = SeriesChartType.Pie;
/* Assign points for the Series */
S1.Points.AddXY(1, 17);
S1.Points.AddXY(2, 27);
S1.Points.AddXY(3, 7);
S1.Points.AddXY(4, 49);
/* Set chart color and other settings as required */
chart.BackColor = Color.Transparent;
CA.BackColor = chart.BackColor;
CA.Area3DStyle.Enable3D = true;
S1.Points[2]["Exploded"] = "true";
/*Assign AntiAliasing to Graphics style for smooth edges*/
chart.AntiAliasing = AntiAliasingStyles.Graphics;
/* Set the image path and save the image as PNG format*/
string imageNameAndPath = string.Concat(Application.StartupPath.Remove(Application.StartupPath.IndexOf("\\bin\\Debug")),
"/TempImages/Image", DateTime.Now.ToString("ddMMyyyyhhmmss") + ".png");
chart.SaveImage(imageNameAndPath, ChartImageFormat.Png);
}
TaW. Please correct me if I'm wrong.
Unfortunately the chart won't draw any transparency directly, so we need to workaround..
If you want to create a PNG with transparent background here is what you can do:
chart1.BackColor = Color.Fuchsia;
chart1.ChartAreas[0].BackColor = chart1.BackColor;
Bitmap bmp = new Bitmap( chart1.ClientSize.Width, chart1.ClientSize.Height);
chart1.AntiAliasing = AntiAliasingStyles.Graphics;
chart1.DrawToBitmap(bmp, chart1.ClientRectangle);
bmp.MakeTransparent(chart1.BackColor);
bmp.Save(yourFileName, ImageFormat.Png);
First we set some areas in the chart to a unique color; if you use fuchsia in your chart (yuck!), pick some other color.
Then we create a Bitmap to hold the image.
Now we turn anti-aliasing off for the text; this help to avoid funny colors when we turn the background pixels to tranparent.
Now we tell the chart control to draw itself into our bitmap.
Finally we make all pixels transparent that have our special color.
Now we can save to disk..
You may want to look into setting the dpi resolution and the chart size to make the result look nice in your pdf!
Update:
If you want to create the image without acutally showing a Chart control, there is no real problem, either. In fact you can even create a Chart image in a console application, if you include all necessary namespaces etc..
All you need to do is create the Chart in code and set up all necessary properties.
Here is a minimal example:
Chart chart = new Chart();
ChartArea CA = chart.ChartAreas.Add("A1");
Series S1 = chart.Series.Add("S1");
S1.ChartType = SeriesChartType.Pie;
S1.Points.AddXY(1, 17);
S1.Points.AddXY(2, 27);
S1.Points.AddXY(3, 7);
S1.Points.AddXY(4, 49);
chart.BackColor = Color.Fuchsia;
CA.BackColor = chart.BackColor;
CA.Area3DStyle.Enable3D = true;
S1.Points[2]["Exploded"] = "true";
Bitmap bmp = new Bitmap(chart.Width, chart.Height);
chart.AntiAliasing = AntiAliasingStyles.None;
chart.DrawToBitmap(bmp, chart.ClientRectangle);
bmp.MakeTransparent(chart.BackColor);
bmp.Save(yourFileName, ImageFormat.Png);

C# DataViusalization Chart Dynamic Sizing

I currently have a chart created in my project as follows:
Chart c = new Chart{
Width = 1000,
Height = 1000,
};
This will create a chart that is 1000 pixels wide and 1000 pixels high. My question is, is there a way to have these values set dynamically so that it could take up a particular portion of the screen? For example if I wanted it to take up 80% of the screen's width and 50% of the height, is there a way to tell it to do that instead of giving static pixel values? If that cannot be done, is there a way to simply have it stretch to the size of its container in the HTML?
So pretty much right after I posted this, I figured out a solution. The chart is displayed in the View via <img> tag, so I can set the style width and height within that tag to change the size of the displayed chart

How to resize c# marker images?

I am trying to make a neat little bar graph with unique markers on the columns.
I used a 20x20px png image for this purpose and set it with
chart1.Series[0].Points[chart1.Series[0].Points.Count - 1].MarkerImage = imageIWanToUse;
but the marker is huge, tried to use
chart1.Series[0].Points[chart1.Series[0].Points.Count - 1].MarkerSize = 1;
but with no luck, i get this on all of the columns, where can i fix this?
image of a column
You need to make sure that the image you use has the proper dpi setting, so that it fits with your screen's dp, which probably is around 75-96 dpi.
If it looks too large than the dpi of the image is too small..
You can change it in code like this:
Bitmap bmp = (Bitmap) Bitmap.FromFile("D:\\stop32.png");
bmp.SetResolution(50, 50);
bmp.Save("D:\\stop32_50dpi.png");
bmp.SetResolution(250, 250);
bmp.Save("D:\\stop32_250dpi.png");
Series S0 = chart1.Series[0];
S0.Points[chart1.Series[0].Points.Count - 3].MarkerImage = "D:\\stop32.png";
S0.Points[chart1.Series[0].Points.Count - 2].MarkerImage = "D:\\stop32_50.png";
S0.Points[chart1.Series[0].Points.Count - 1].MarkerImage = "D:\\stop32_250.png";
Here are the resulting markers:
The original resolution was 96dpi. (Left marker.)
You will have to watch out for varying screen dpi and use either different images or create the right one dynamically. You can get the current screen dpi e.g. by testing the current Graphics object in a Paint event: Console.WriteLine(e.Graphics.DpiX + " dpi x"); For my screen this resulted in 120 dpi..

How do I add a tooltip or overlay to a specific section of a chart?

I have a chart that displays several lines showing signal strengths over a frequency band.
Each chart is composed of one 'area' and four 'series'. On the parent form there are several graphs like the one shown below. All of them are created dynamically and will have different widths.
What I am trying to do is add a tooltip or annotation (or something) when the mouse hovers over a specific area of the chart as shown in the mockup below:
If the mouse moved to the other side of the chart a different channel number and frequency would be shown in a box surrounding that area of the chart.
It doesn't have to be exactly as shown in the mockup although an outline would be preferred in order to show the user how wide the channel is regardless of the waveform shown in that area at the time. For example, the waveform shown above might only be 8MHz wide but channel 1 itself might have an allocation that is 10MHz wide (the device varies its bandwidth based on its offered load.)
The X axis is MHz and a channel is defined in terms of MHz so it would be ideal to define the outline in terms of the X axis instead of pixels.
Also, note that this is a realtime chart that is updated up to 10 times per second. Therefore it would be best if the information was not required to be updated each time new data arrived.
I was able to combine a couple of items to make the following solution:
[credit LICEcap]
The highlight is a rectangle filled in the 'OnPaint' method of the chart control.
The text is a simple TextAnnotation that is applied during the mousemove event.
It took quite a bit of coordinate conversion to get all the pieces in the right spot - especially the text. I needed to convert between pixels, position and value.
The first conversion was to pixels in order to center the text using MeasureString. I then converted it from pixel location to X axis value and then needed to convert it to position since the annotation requires using 'position' coordinates. There is not a function to convert from pixels to position. There is a pixels to value and a value to position which is the way I went.
I don't claim this to be the best or even a proper way to do it but it works. If anyone else has a better solution or a way to improve my code please post.
Here's my code for positioning the text:
double temp = chart1.ChartAreas[0].AxisX.ValueToPixelPosition(Convert.ToDouble(ce.sChannelFrequency) * 1000);
using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(new Bitmap(1, 1))) {
SizeF size = graphics.MeasureString(freq.Text, new Font("eurostile", 13, FontStyle.Bold, GraphicsUnit.Pixel));
temp -= (size.Width/2+10);
}
if (temp < 0) temp = 0;
temp = chart1.ChartAreas[0].AxisX.PixelPositionToValue(temp);
freq.X = chart1.ChartAreas[0].AxisX.ValueToPosition(temp);

Categories

Resources