根据你的需求,我们需要对代码进行以下改进:
1. **纵坐标刻度均匀分布**:确保纵坐标的刻度范围能够适配数据的最大值和最小值,并且分布均匀。
2. **横坐标使用斜标注**:当日期较多时,横坐标标签可能会重叠,因此将日期标签旋转一定角度(例如45度)以避免重叠。
以下是改进后的代码:
### 回答问题
```python
import svgwrite
from math import radians, cos, sin
def generate_svg(data, filename="output.svg"):
# 提取日期、基准数据和真实数据
dates = [list(item.keys())[0] for item in data]
base_data = [int(list(item.values())[0][1]) for item in data]
real_data = [int(list(item.values())[0][0]) for item in data]
# 参数校验
if len(dates) != len(base_data) or len(dates) != len(real_data):
raise ValueError("日期、基准数据和真实数据的长度必须一致")
# SVG配置
width, height = 800, 400
padding = 50
max_value = max(max(base_data), max(real_data))
min_value = min(min(base_data), min(real_data))
y_scale = (height - 2 * padding) / (max_value - min_value)
x_scale = (width - 2 * padding) / len(dates)
# 创建SVG画布
dwg = svgwrite.Drawing(filename, profile='tiny')
# 绘制网格和坐标轴
dwg.add(dwg.line((padding, padding), (padding, height - padding), stroke=svgwrite.rgb(100, 100, 100, '%')))
dwg.add(dwg.line((padding, height - padding), (width - padding, height - padding), stroke=svgwrite.rgb(100, 100, 100, '%')))
# 添加纵坐标刻度
num_ticks = 6
for i in range(num_ticks):
value = min_value + i * (max_value - min_value) / (num_ticks - 1)
y_pos = height - padding - (value - min_value) * y_scale
dwg.add(dwg.line((padding - 5, y_pos), (padding, y_pos), stroke=svgwrite.rgb(100, 100, 100, '%')))
dwg.add(dwg.text(f"{value:.0f}", insert=(padding - 30, y_pos + 5), fill='black'))
# 绘制基准数据折线(灰色)
base_points = [(padding + x * x_scale, height - padding - (base_data[x] - min_value) * y_scale) for x in range(len(dates))]
dwg.add(dwg.polyline(base_points, stroke=svgwrite.rgb(128, 128, 128, '%'), fill='none', stroke_width=2))
# 绘制真实数据折线(根据条件选择颜色)
real_points_green = []
real_points_red = []
for x in range(len(dates)):
y = real_data[x]
color = 'green' if y > base_data[x] else 'red'
point = (padding + x * x_scale, height - padding - (y - min_value) * y_scale)
if color == 'green':
real_points_green.append(point)
else:
real_points_red.append(point)
if real_points_green:
dwg.add(dwg.polyline(real_points_green, stroke=svgwrite.rgb(0, 255, 0, '%'), fill='none', stroke_width=2))
if real_points_red:
dwg.add(dwg.polyline(real_points_red, stroke=svgwrite.rgb(255, 0, 0, '%'), fill='none', stroke_width=2))
# 添加日期标签(斜标注)
label_angle = 45 # 标签旋转角度
for x in range(len(dates)):
text = dates[x]
x_pos = padding + x * x_scale
y_pos = height - padding + 20
# 计算旋转后的位置
text_length = len(text) * 7 # 假设每个字符宽度为7
rotated_x = x_pos - text_length * cos(radians(label_angle)) / 2
rotated_y = y_pos + text_length * sin(radians(label_angle)) / 2
dwg.add(dwg.text(text, insert=(rotated_x, rotated_y), fill='black', text_anchor="middle", transform=f"rotate({-label_angle} {x_pos} {y_pos})"))
# 保存SVG文件
dwg.save()
# 示例调用
data = [
{"2025-05-15": ["1100", "1000"]}, {"2025-05-16": ["1100", "1000"]},
{"2025-05-17": ["400", "1000"]}, {"2025-05-18": ["1100", "1000"]},
{"2025-05-19": ["1100", "1000"]}, {"2025-05-20": ["400", "1000"]},
{"2025-05-21": ["127", "1000"]}, {"2025-05-22": ["1100", "1000"]},
{"2025-05-23": ["200", "1000"]}, {"2025-05-24": ["1100", "1000"]},
{"2025-05-25": ["1100", "1000"]}, {"2025-05-26": ["1100", "1000"]},
{"2025-05-27": ["1100", "1000"]}, {"2025-05-28": ["1100", "1000"]},
{"2025-05-29": ["1100", "1000"]}
]
generate_svg(data)
```
### 给出解释
1. **数据提取**:从输入的`data`列表中提取日期、基准数据和真实数据。
2. **纵坐标刻度**:通过计算数据的最大值和最小值,生成均匀分布的刻度。
3. **横坐标斜标注**:为了避免日期标签重叠,使用`transform`属性将文本旋转45度。
4. **动态调整比例**:根据数据的最大值和最小值动态调整y轴的比例,确保刻度均匀分布。
###