如何解决读取一个csv文件并计算值之间的差异,以制作饼图
我正在申请一份工作,以记录人们在做什么的时间。 (即有空,忙,现场,返回站点,快速休息,午餐休息)。
发生的事情是,当用户单击按钮时,它将用户名写入文件,然后写入逗号,然后写入时间(小时,分钟和秒)。例如:
{{1}}
我已经弄清楚了如何仅显示用户的状态更新,然后使用以下内容填充到标签中:
{{1}}
如果可能的话,我想做的是找出每个用户花费的时间差,然后用它来在图表中填充饼图,以便它可以显示饼图中每个段的大小,用户在每种状态下花费。因此,在我的代码中,我可以以某种方式计算用户在每种状态下花费的总时间,并以此为基础创建饼图吗?我有一个想法,要读入每一行,然后检查状态并计算出每个状态的变化,然后将其添加到变量中以填充饼图,但无法弄清楚这一点。任何帮助将不胜感激!谢谢。
解决方法
这可以通过在给定状态下汇总每个员工的工期来实现,最好是CSV文件具有列标题,然后可以使用Schema.ini并使用ODBC text driver
查询数据,这是最小的可重现示例:
sampledata.csv:
Name,Status,Time
John,Available,10:10:26
Dave,10:15:40
Steve,10:44:14
John,Busy,12:13:28
Steve,QuickBreak,12:15:25
John,12:18:03
Dave,12:18:03
Steve,12:28:16
John,Offline,17:00:00
Dave,17:00:00
Steve,17:00:00
Schema.ini:
[sampledata.csv]
Format=CSVDelimited
ColNameHeader=True
Col1 = "Name" Text
Col2 = "Status" Text
Col3 = "TimeStamp" DateTime
员工类别和状态枚举:
class Employee
{
public static List<Employee> Employees { get; private set; } = new List<Employee>();
public string Name { get; }
public StatusEnum Status { get; }
public DateTime TimeStamp { get; }
public TimeSpan Duration { get; private set; }
public Employee(string name,StatusEnum status,DateTime time)
{
this.Name = name;
this.Status = status;
this.TimeStamp = time;
Employees.Add(this);
}
public static Dictionary<string,double> GetEmployeeStatusSummary(Employee employee)
{
var dict = new Dictionary<string,double>();
foreach (var emp in Employees.Where(e => e.Name == employee.Name))
{
if (dict.ContainsKey(emp.Status.ToString()))
{
dict[emp.Status.ToString()] += emp.Duration.TotalMinutes;
}
else
{
dict.Add(emp.Status.ToString(),emp.Duration.TotalMinutes);
}
}
return dict;
}
public static void UpdateAllEmployeesDuration()
{
Employees = Employees.OrderBy(e => e.Name).ThenBy(e => e.TimeStamp).ToList();
TimeSpan duration;
for (int i = 0; i < Employees.Count - 1; i++)
{
if (Employees[i].Name == Employees[i + 1].Name)
{
duration = Employees[i + 1].TimeStamp - Employees[i].TimeStamp;
Employees[i].Duration = duration;
}
}
}
override public string ToString()
{
return this.Name;
}
}
enum StatusEnum
{
Available,Break,Offline
}
然后在带有饼图的Form
中,使用刷新按钮触发流程->查询CSV文件,使用员工姓名更新下拉列表并清除图表,如果CSV文件经常更新并且用户经常使用,则很有用想要查看新数据。
ComboBox
事件SelectedIndexChanged
将更新图表以显示所选员工的数据。
private void btn_Refresh_Click(object sender,EventArgs e)
{
var csvPath = Path.GetDirectoryName(Application.ExecutablePath);
var connStr = "Driver={Microsoft Text Driver (*.txt; *.csv)}; Extensions=asc,csv,tab,txt; Dbq=";
var dt = new DataTable();
using (var conn = new OdbcConnection(connStr + csvPath))
using (var odba = new OdbcDataAdapter("SELECT * FROM sampledata.csv",conn))
{
odba.Fill(dt);
}
foreach (DataRow row in dt.Rows)
{
var name = row[nameof(Employee.Name)].ToString();
Enum.TryParse(row[nameof(Employee.Status)].ToString(),out StatusEnum status);
var duration = (DateTime)row[nameof(Employee.TimeStamp)];
new Employee(name,status,duration);
}
Employee.UpdateAllEmployeesDuration();
this.chart_Pie.Series.Clear();
this.cbx_Names.DataSource = Employee.Employees.GroupBy(emp => emp.Name)
.Select(g => g.First())
.ToList();
}
private void cbx_Names_SelectedIndexChanged(object sender,EventArgs e)
{
var employee = (Employee)cbx_Names.SelectedItem;
if (this.chart_Pie.Series.IsUniqueName(employee.Name) == false)
{
foreach (var series in this.chart_Pie.Series)
{
if (series.Name.Equals(employee.Name,StringComparison.OrdinalIgnoreCase))
{
series.Enabled = true;
}
else
{
series.Enabled = false;
}
}
}
else
{
foreach (var ser in this.chart_Pie.Series)
{
ser.Enabled = false;
}
var points = Employee.GetEmployeeStatusSummary(employee);
var series = new Series(employee.Name);
series.ChartType = SeriesChartType.Pie;
this.chart_Pie.Series.Add(series);
this.chart_Pie.Series[employee.Name].Points.DataBindXY(points.Keys,points.Values);
}
}
最后的结果:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。